diff --git a/src/lib/components/VehiclesContent.svelte b/src/lib/components/VehiclesContent.svelte index 3f51391..249e417 100644 --- a/src/lib/components/VehiclesContent.svelte +++ b/src/lib/components/VehiclesContent.svelte @@ -2,17 +2,22 @@ import { onMount } from 'svelte'; // Props - export let user = null; +export let user = null; let vehicles = []; let units = []; let loading = true; let error = ''; + let unitWarning = ''; let showAddModal = false; let showEditModal = false; let selectedVehicle = null; - // Form değişkenleri + let isAdmin = false; + let isGoodsManager = false; + let managerUnitId = null; + let managerUnitName = ''; + let formData = { brand: '', model: '', @@ -26,6 +31,37 @@ let formData = { kislik_mukannen: 0 }; +$: { + isAdmin = user?.role === 'admin'; + isGoodsManager = user?.role === 'goods_manager'; + managerUnitId = isGoodsManager && user?.unit_id ? parseInt(user.unit_id) : null; + managerUnitName = isGoodsManager ? (user?.unit_name || getUnitName(user?.unit_id)) : ''; +} + +$: { + if (isGoodsManager && !managerUnitId) { + unitWarning = 'Birlik bilginiz bulunamadı. Lütfen sistem yöneticisine başvurun.'; + } else { + unitWarning = ''; + } +} + +$: { + const managerUnitValue = managerUnitId ? managerUnitId.toString() : ''; + if ( + isGoodsManager && + managerUnitId && + formData.unit_id !== managerUnitValue && + !showEditModal && + (!showAddModal || (showAddModal && !formData.unit_id)) + ) { + formData = { + ...formData, + unit_id: managerUnitValue + }; + } +} + onMount(async () => { await loadUnits(); await loadVehicles(); @@ -37,6 +73,9 @@ async function loadUnits() { if (response.ok) { const data = await response.json(); units = data.units || []; + if (isGoodsManager && managerUnitId) { + managerUnitName = getUnitName(managerUnitId, units); + } } } catch (err) { console.error('Load units error:', err); @@ -48,7 +87,15 @@ async function loadUnits() { const response = await fetch('/api/vehicles'); if (response.ok) { const data = await response.json(); - vehicles = data.vehicles; + let fetchedVehicles = data.vehicles || []; + if (isGoodsManager) { + if (managerUnitId) { + fetchedVehicles = fetchedVehicles.filter(vehicle => vehicle.unit_id === managerUnitId); + } else { + fetchedVehicles = []; + } + } + vehicles = fetchedVehicles; } else { error = 'Araçlar yüklenemedi.'; } @@ -66,7 +113,7 @@ function resetForm() { model: '', year: new Date().getFullYear(), plate: '', - unit_id: '', + unit_id: isGoodsManager && managerUnitId ? managerUnitId.toString() : '', fuel_type: 'Benzin', fuel_capacity: 50, current_fuel: 0, @@ -115,11 +162,21 @@ function validateMukannen(value) { function getUnitName(unitId, unitList = units) { const id = parseInt(unitId); - return unitList.find((unit) => unit.id === id)?.name || 'Belirtilmemiş'; + const unitName = unitList.find((unit) => unit.id === id)?.name; + if (unitName) return unitName; + if (isGoodsManager && managerUnitId === id) { + return managerUnitName || 'Belirtilmemiş'; + } + return 'Belirtilmemiş'; } - async function handleAddVehicle() { - if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.unit_id || !formData.fuel_type || !formData.fuel_capacity) { +async function handleAddVehicle() { + if (isGoodsManager && !managerUnitId) { + error = 'Birlik bilginiz bulunamadı. Lütfen sistem yöneticisine başvurun.'; + return; + } + + if (!formData.brand || !formData.model || !formData.year || !formData.plate || (!isGoodsManager && !formData.unit_id) || !formData.fuel_type || !formData.fuel_capacity) { error = 'Tüm zorunlu alanları doldurun.'; return; } @@ -132,7 +189,7 @@ function getUnitName(unitId, unitList = units) { try { const payload = { ...formData, - unit_id: parseInt(formData.unit_id) + unit_id: isGoodsManager && managerUnitId ? managerUnitId : parseInt(formData.unit_id) }; const response = await fetch('/api/vehicles', { method: 'POST', @@ -157,8 +214,13 @@ function getUnitName(unitId, unitList = units) { } } - async function handleUpdateVehicle() { - if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.unit_id || !formData.fuel_type || !formData.fuel_capacity) { +async function handleUpdateVehicle() { + if (isGoodsManager && !managerUnitId) { + error = 'Birlik bilginiz bulunamadı. Lütfen sistem yöneticisine başvurun.'; + return; + } + + if (!formData.brand || !formData.model || !formData.year || !formData.plate || (!isGoodsManager && !formData.unit_id) || !formData.fuel_type || !formData.fuel_capacity) { error = 'Tüm zorunlu alanları doldurun.'; return; } @@ -172,7 +234,7 @@ function getUnitName(unitId, unitList = units) { const payload = { id: selectedVehicle.id, ...formData, - unit_id: parseInt(formData.unit_id) + unit_id: isGoodsManager && managerUnitId ? managerUnitId : parseInt(formData.unit_id) }; const response = await fetch('/api/vehicles', { method: 'PUT', @@ -233,7 +295,7 @@ function getUnitName(unitId, unitList = units) { {vehicles.length} Araç - + @@ -247,6 +309,11 @@ function getUnitName(unitId, unitList = units) { {error} {/if} + {#if unitWarning} + + {unitWarning} + + {/if} {#if loading} @@ -364,20 +431,32 @@ function getUnitName(unitId, unitList = units) { required /> - - Birlik - - Birlik Seçin - {#each units as unit} - {unit.name} - {/each} - - + {#if isAdmin} + + Birlik + + Birlik Seçin + {#each units as unit} + {unit.name} + {/each} + + + {:else if isGoodsManager} + + Birlik + + + {/if} Yakıt Tipi - - Birlik - - Birlik Seçin - {#each units as unit} - {unit.name} - {/each} - - + {#if isAdmin} + + Birlik + + Birlik Seçin + {#each units as unit} + {unit.name} + {/each} + + + {:else if isGoodsManager} + + Birlik + + + {/if} Yakıt Tipi + + navigateTo("goods-manager-vehicles")} + class:active={showGoodsManagerVehicles} + > + + + + + + + + + Araç Yönetimi + + + {:else if user.role === "goods_manager" && showGoodsManagerVehicles} + {:else if user.role === "goods_manager" && showMonthlyReport} diff --git a/src/server.js b/src/server.js index bc06c72..a1f8574 100644 --- a/src/server.js +++ b/src/server.js @@ -12,7 +12,8 @@ import { addGoodsManager, updateGoodsManager, deleteGoodsManager, - findGoodsManagerById + findGoodsManagerById, + findGoodsManagerByUsername } from './lib/data/goodsManagers.js'; // Units veritabanı @@ -292,12 +293,37 @@ async function initializeDatabase() { password TEXT NOT NULL, role TEXT NOT NULL, full_name TEXT, + unit_id INTEGER, + unit_name TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, is_active BOOLEAN DEFAULT 1 )`, (err) => { if (err) reject(err); }); + // Ensure optional columns exist (for older databases) + db.all('PRAGMA table_info(users)', (pragmaErr, columns) => { + if (pragmaErr) { + console.error('⚠️ Unable to inspect users table columns:', pragmaErr); + } else { + const colNames = columns.map(col => col.name); + const ensureColumn = (name, definition) => { + if (!colNames.includes(name)) { + db.run(`ALTER TABLE users ADD COLUMN ${definition}`, (alterErr) => { + if (alterErr) { + console.warn(`⚠️ Could not add column ${name}:`, alterErr.message); + } else { + console.log(`ℹ️ Added column ${name} to users table.`); + } + }); + } + }; + + ensureColumn('unit_id', 'unit_id INTEGER'); + ensureColumn('unit_name', 'unit_name TEXT'); + } + }); + // Yakıt fişleri tablosu db.run(`CREATE TABLE IF NOT EXISTS fuel_slips ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -328,24 +354,28 @@ async function initializeDatabase() { // Tablolar oluşturulduktan sonra kullanıcıları ekle setTimeout(async () => { // Örnek kullanıcıları ekle - const users = [ - { username: 'admin', password: 'admin123', role: 'admin', full_name: 'Sistem Yöneticisi' }, - { username: 'fuel', password: 'fuel123', role: 'fuel_manager', full_name: 'Yakıt Sorumlusu' }, - { username: 'goods', password: 'goods123', role: 'goods_manager', full_name: 'Mal Sorumlusu' }, - { username: 'ibrahim_kara', password: 'kara123', role: 'goods_manager', full_name: 'İbrahim Kara' } - ]; + const users = [ + { username: 'admin', password: 'admin123', role: 'admin', full_name: 'Sistem Yöneticisi' }, + { username: 'fuel', password: 'fuel123', role: 'fuel_manager', full_name: 'Yakıt Sorumlusu' }, + { username: 'goods', password: 'goods123', role: 'goods_manager', full_name: 'Ali Veli', unit_id: 1, unit_name: '1. Motorlu Piyade Tugayı' }, + { username: 'ibrahim_kara', password: 'kara123', role: 'goods_manager', full_name: 'İbrahim Kara', unit_id: 2, unit_name: '2. Zırhlı Tabur' }, + { username: 'osmankocak', password: 'osman123', role: 'goods_manager', full_name: 'Osman Koçak', unit_id: 3, unit_name: '3. Komutanlık' } + ]; - // Her kullanıcıyı kontrol et ve yoksa ekle - for (const user of users) { - const hashedPassword = await bcrypt.hash(user.password, 10); + // Her kullanıcıyı kontrol et ve yoksa ekle + for (const user of users) { + const hashedPassword = await bcrypt.hash(user.password, 10); - db.get('SELECT id FROM users WHERE username = ?', [user.username], (err, row) => { - if (!row) { - db.run('INSERT INTO users (username, password, role, full_name) VALUES (?, ?, ?, ?)', - [user.username, hashedPassword, user.role, user.full_name]); - } - }); - } + db.get('SELECT id, unit_id, unit_name FROM users WHERE username = ?', [user.username], (err, row) => { + if (!row) { + db.run('INSERT INTO users (username, password, role, full_name, unit_id, unit_name) VALUES (?, ?, ?, ?, ?, ?)', + [user.username, hashedPassword, user.role, user.full_name, user.unit_id || null, user.unit_name || null]); + } else if ((user.unit_id && !row.unit_id) || (user.unit_name && !row.unit_name)) { + db.run('UPDATE users SET unit_id = COALESCE(unit_id, ?), unit_name = COALESCE(unit_name, ?) WHERE username = ?', + [user.unit_id || null, user.unit_name || null, user.username]); + } + }); + } resolve(); }, 100); }); @@ -382,23 +412,35 @@ app.post('/api/login', async (req, res) => { id: user.id, username: user.username, role: user.role, - full_name: user.full_name + full_name: user.full_name, + unit_id: user.unit_id ? parseInt(user.unit_id) : null, + unit_name: user.unit_name || null }; - // Eğer goods_manager ise, goods_managers API'den gerçek ID'yi al + // Eğer goods_manager ise, goodsManagers verisinden profil bilgilerini al if (user.role === 'goods_manager') { - try { - const goodsManagersRes = await fetch('http://localhost:3000/api/goods-managers'); - if (goodsManagersRes.ok) { - const goodsData = await goodsManagersRes.json(); - const goodsManager = goodsData.goodsManagers?.find(gm => gm.username === user.username); - if (goodsManager) { - sessionUser.id = goodsManager.id; // goods_manager ID'sini kullan - console.log(`✅ Goods manager logged in: ${user.full_name} (ID: ${goodsManager.id})`); - } + const goodsManager = findGoodsManagerByUsername(user.username); + if (goodsManager) { + sessionUser.goods_manager_profile_id = goodsManager.id; + sessionUser.id = goodsManager.id; + if (!sessionUser.unit_id || !sessionUser.unit_name) { + sessionUser.unit_id = goodsManager.unit_id; + sessionUser.unit_name = goodsManager.unit_name; + sessionUser.rank = goodsManager.rank; + db.run('UPDATE users SET unit_id = ?, unit_name = ? WHERE id = ?', [ + goodsManager.unit_id, + goodsManager.unit_name, + user.id + ]); + } + if (!sessionUser.rank) { + sessionUser.rank = goodsManager.rank; + } + console.log(`✅ Goods manager logged in: ${goodsManager.full_name} (ID: ${goodsManager.id})`); + } else { + if (!sessionUser.unit_id || !sessionUser.unit_name) { + console.warn(`⚠️ Goods manager profile not found for username: ${user.username}`); } - } catch (fetchError) { - console.warn('⚠️ Could not fetch goods manager ID:', fetchError); } } @@ -536,11 +578,21 @@ app.post('/api/units', async (req, res) => { // Mal sorumlusu kullanıcı olarak ekle await new Promise((resolve, reject) => { - db.run('INSERT INTO users (username, password, role, full_name) VALUES (?, ?, ?, ?)', - [username, hashedPassword, 'goods_manager', full_name], (err) => { + db.run( + 'INSERT INTO users (username, password, role, full_name, unit_id, unit_name) VALUES (?, ?, ?, ?, ?, ?)', + [ + username.trim(), + hashedPassword, + 'goods_manager', + full_name.trim(), + newUnit.id, + newUnit.name + ], + (err) => { if (err) reject(err); else resolve(); - }); + } + ); }); console.log(`✅ Mal sorumlusu kullanıcı oluşturuldu: ${username}`); @@ -597,6 +649,12 @@ app.put('/api/units', async (req, res) => { return res.status(404).json({ message: 'Birlik bulunamadı.' }); } + // Mevcut komutan bilgisini sakla (DB senkronu için) + const previousUnitState = { + ...units[unitIndex], + commander: { ...units[unitIndex].commander } + }; + // Birlik güncelle const updatedCommander = { full_name: full_name.trim(), @@ -607,6 +665,7 @@ app.put('/api/units', async (req, res) => { username: username.trim(), password: password.trim() }; + const previousCommanderUsername = previousUnitState?.commander?.username || updatedCommander.username; units[unitIndex] = { ...units[unitIndex], @@ -617,31 +676,41 @@ app.put('/api/units', async (req, res) => { commander: updatedCommander }; - // Eğer kullanıcı adı veya şifre değişmişse, kullanıcıyı güncelle - const oldCommander = units[unitIndex].commander; - if (oldCommander.username !== username || password !== oldCommander.password) { - try { - const hashedPassword = await bcrypt.hash(password, 10); + // Mal sorumlusu kullanıcı kaydını güncelle + try { + const hashedPassword = await bcrypt.hash(password, 10); - // Kullanıcıyı güncelle - await new Promise((resolve, reject) => { - db.run('UPDATE users SET username = ?, password = ?, full_name = ? WHERE username = ?', - [username, hashedPassword, full_name, oldCommander.username], (err) => { - if (err) reject(err); - else resolve(); - }); - }); + await new Promise((resolve, reject) => { + db.run( + `UPDATE users + SET username = ?, password = ?, full_name = ?, unit_id = ?, unit_name = ? + WHERE username = ?`, + [ + updatedCommander.username, + hashedPassword, + updatedCommander.full_name, + units[unitIndex].id, + units[unitIndex].name, + previousCommanderUsername + ], + function (err) { + if (err) { + return reject(err); + } + if (this.changes === 0) { + return reject(new Error('Mal sorumlusu kullanıcı kaydı bulunamadı.')); + } + return resolve(); + } + ); + }); - console.log(`✅ Mal sorumlusu kullanıcı güncellendi: ${username}`); - } catch (userError) { - console.error('❌ Mal sorumlusu kullanıcı güncelleme hatası:', userError); - // Kullanıcı güncellenemezse, birlik güncellemesi geri alınsın - units[unitIndex] = { - ...units[unitIndex], - commander: oldCommander - }; - return res.status(500).json({ message: 'Mal sorumlusu kullanıcı güncellenemedi.' }); - } + console.log(`✅ Mal sorumlusu kullanıcı güncellendi: ${updatedCommander.username}`); + } catch (userError) { + console.error('❌ Mal sorumlusu kullanıcı güncelleme hatası:', userError); + // Kullanıcı güncellenemezse, birlik güncellemesi geri alınsın + units[unitIndex] = previousUnitState; + return res.status(500).json({ message: 'Mal sorumlusu kullanıcı güncellenemedi.' }); } res.json({ @@ -1431,10 +1500,29 @@ app.delete('/api/fuel-slips', async (req, res) => { // Vehicles API endpoint'leri +// Yardımcı: goods manager birlik bilgisi al +function getGoodsManagerUnit(req) { + const sessionUser = req.session?.user; + if (!sessionUser || sessionUser.role !== 'goods_manager') { + return { isGoodsManager: false, unitId: null }; + } + const unitId = sessionUser.unit_id ? parseInt(sessionUser.unit_id) : null; + return { isGoodsManager: true, unitId }; +} + // GET - Tüm araçları listele app.get('/api/vehicles', (req, res) => { - // Yetki kontrolü (temporary - will be implemented with proper session) - res.json({ vehicles }); + const { isGoodsManager, unitId } = getGoodsManagerUnit(req); + + if (isGoodsManager && !unitId) { + return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisi ile iletişime geçin.' }); + } + + const filteredVehicles = isGoodsManager + ? vehicles.filter(vehicle => vehicle.unit_id === unitId) + : vehicles; + + res.json({ vehicles: filteredVehicles }); }); // POST - Yeni araç ekle @@ -1442,6 +1530,7 @@ app.post('/api/vehicles', (req, res) => { // Yetki kontrolü (temporary - will be implemented with proper session) try { + const { isGoodsManager, unitId: managerUnitId } = getGoodsManagerUnit(req); const { brand, model, @@ -1458,12 +1547,18 @@ app.post('/api/vehicles', (req, res) => { driver_name } = req.body; + const resolvedUnitId = isGoodsManager ? managerUnitId : parseInt(unit_id); + // Validasyon - if (!brand || !model || !year || !plate || !unit_id || !fuel_type || !fuel_capacity) { + if (!brand || !model || !year || !plate || (!resolvedUnitId && !isGoodsManager) || !fuel_type || !fuel_capacity) { return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' }); } - const targetUnit = units.find(u => u.id === parseInt(unit_id)); + if (isGoodsManager && !managerUnitId) { + return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisi ile iletişime geçin.' }); + } + + const targetUnit = units.find(u => u.id === resolvedUnitId); if (!targetUnit) { return res.status(400).json({ message: 'Geçerli bir birlik seçin.' }); } @@ -1492,7 +1587,7 @@ app.post('/api/vehicles', (req, res) => { model: model.trim(), year: parseInt(year), plate: plate.trim().toUpperCase(), - unit_id: parseInt(unit_id), + unit_id: resolvedUnitId, fuel_type: fuel_type.trim(), fuel_capacity: parseInt(fuel_capacity), current_fuel: parseInt(current_fuel) || 0, @@ -1522,6 +1617,7 @@ app.put('/api/vehicles', (req, res) => { // Yetki kontrolü (temporary - will be implemented with proper session) try { + const { isGoodsManager, unitId: managerUnitId } = getGoodsManagerUnit(req); const { id, brand, @@ -1539,12 +1635,18 @@ app.put('/api/vehicles', (req, res) => { driver_name } = req.body; + const resolvedUnitId = isGoodsManager ? managerUnitId : parseInt(unit_id); + // Validasyon - if (!id || !brand || !model || !year || !plate || !unit_id || !fuel_type || !fuel_capacity) { + if (!id || !brand || !model || !year || !plate || (!resolvedUnitId && !isGoodsManager) || !fuel_type || !fuel_capacity) { return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' }); } - const targetUnit = units.find(u => u.id === parseInt(unit_id)); + if (isGoodsManager && !managerUnitId) { + return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisine başvurun.' }); + } + + const targetUnit = units.find(u => u.id === resolvedUnitId); if (!targetUnit) { return res.status(400).json({ message: 'Geçerli bir birlik seçin.' }); } @@ -1563,6 +1665,10 @@ app.put('/api/vehicles', (req, res) => { return res.status(404).json({ message: 'Araç bulunamadı.' }); } + if (isGoodsManager && vehicles[vehicleIndex].unit_id !== managerUnitId) { + return res.status(403).json({ message: 'Bu aracı güncelleme yetkiniz yok.' }); + } + // Plaka tekrar kontrolü (diğer araçlar için) const existingVehicle = vehicles.find(v => v.id !== parseInt(id) && v.plate.toLowerCase() === plate.toLowerCase() @@ -1579,7 +1685,7 @@ app.put('/api/vehicles', (req, res) => { model: model.trim(), year: parseInt(year), plate: plate.trim().toUpperCase(), - unit_id: parseInt(unit_id), + unit_id: resolvedUnitId, fuel_type: fuel_type.trim(), fuel_capacity: parseInt(fuel_capacity), current_fuel: parseInt(current_fuel) || 0, @@ -1612,6 +1718,7 @@ app.delete('/api/vehicles', (req, res) => { // Yetki kontrolü (temporary - will be implemented with proper session) try { + const { isGoodsManager, unitId: managerUnitId } = getGoodsManagerUnit(req); const { id } = req.body; if (!id) { @@ -1624,6 +1731,15 @@ app.delete('/api/vehicles', (req, res) => { return res.status(404).json({ message: 'Araç bulunamadı.' }); } + if (isGoodsManager) { + if (!managerUnitId) { + return res.status(400).json({ message: 'Birlik bilginiz tanımlı değil. Lütfen sistem yöneticisine başvurun.' }); + } + if (vehicles[vehicleIndex].unit_id !== managerUnitId) { + return res.status(403).json({ message: 'Bu aracı silme yetkiniz yok.' }); + } + } + // Araç sil const deletedVehicle = vehicles.splice(vehicleIndex, 1)[0];