208 lines
7.1 KiB
JavaScript
Executable File
208 lines
7.1 KiB
JavaScript
Executable File
// Staff Users API Routes - Dynamic User Management
|
|
import express from 'express';
|
|
import pool from '../db.js';
|
|
import crypto from 'crypto';
|
|
|
|
const router = express.Router();
|
|
|
|
// Simple password hashing (for demo - in production use bcrypt)
|
|
const hashPassword = (password) => {
|
|
return crypto.createHash('sha256').update(password).digest('hex');
|
|
};
|
|
|
|
// Helper to parse assigned_classes JSON
|
|
const parseAssignedClasses = (row) => {
|
|
try {
|
|
return row.assigned_classes ? JSON.parse(row.assigned_classes) : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
// GET /api/staff - Get all staff users
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const [rows] = await pool.query(
|
|
'SELECT id, username, name, role, phone, assigned_classes, is_active, created_at FROM staff_users ORDER BY created_at DESC'
|
|
);
|
|
// Parse assigned_classes for each staff
|
|
const result = rows.map(row => ({
|
|
...row,
|
|
assignedClasses: parseAssignedClasses(row),
|
|
assigned_classes: undefined // Remove raw field
|
|
}));
|
|
res.json(result);
|
|
} catch (error) {
|
|
console.error('GET /api/staff Error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// GET /api/staff/guru-bk/by-class/:className - Find Guru BK by class
|
|
router.get('/guru-bk/by-class/:className', async (req, res) => {
|
|
try {
|
|
const { className } = req.params;
|
|
|
|
// Find all GURU_BK who have this class in their assigned_classes
|
|
const [rows] = await pool.query(
|
|
`SELECT id, username, name, role, phone, assigned_classes, is_active
|
|
FROM staff_users
|
|
WHERE role = 'GURU_BK' AND is_active = TRUE`
|
|
);
|
|
|
|
// Filter to find Guru BK with matching class
|
|
const matchingGuruBK = rows.filter(row => {
|
|
const assignedClasses = parseAssignedClasses(row);
|
|
return assignedClasses.includes(className);
|
|
}).map(row => ({
|
|
id: row.id,
|
|
name: row.name,
|
|
phone: row.phone,
|
|
assignedClasses: parseAssignedClasses(row)
|
|
}));
|
|
|
|
if (matchingGuruBK.length > 0) {
|
|
// Return the first matching Guru BK
|
|
res.json({ found: true, guruBK: matchingGuruBK[0] });
|
|
} else {
|
|
// No matching Guru BK found, return first active GURU_BK as fallback
|
|
const [fallback] = await pool.query(
|
|
`SELECT id, name, phone, assigned_classes
|
|
FROM staff_users
|
|
WHERE role = 'GURU_BK' AND is_active = TRUE
|
|
LIMIT 1`
|
|
);
|
|
if (fallback.length > 0) {
|
|
res.json({
|
|
found: false,
|
|
fallback: true,
|
|
guruBK: {
|
|
id: fallback[0].id,
|
|
name: fallback[0].name,
|
|
phone: fallback[0].phone,
|
|
assignedClasses: parseAssignedClasses(fallback[0])
|
|
}
|
|
});
|
|
} else {
|
|
res.json({ found: false, guruBK: null });
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('GET /api/staff/guru-bk/by-class Error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// POST /api/staff - Create new staff user
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const { username, password, name, role, phone, assignedClasses } = req.body;
|
|
|
|
if (!username || !password || !name || !role) {
|
|
return res.status(400).json({ error: 'Username, password, name, dan role wajib diisi.' });
|
|
}
|
|
|
|
// Check if username already exists
|
|
const [existing] = await pool.query('SELECT id FROM staff_users WHERE username = ?', [username]);
|
|
if (existing.length > 0) {
|
|
return res.status(400).json({ error: 'Username sudah digunakan.' });
|
|
}
|
|
|
|
const id = crypto.randomUUID();
|
|
const hashedPassword = hashPassword(password);
|
|
const assignedClassesJson = assignedClasses && Array.isArray(assignedClasses)
|
|
? JSON.stringify(assignedClasses)
|
|
: null;
|
|
|
|
await pool.query(
|
|
'INSERT INTO staff_users (id, username, password, name, role, phone, assigned_classes) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
|
[id, username, hashedPassword, name, role, phone || null, assignedClassesJson]
|
|
);
|
|
|
|
res.json({ success: true, id, message: 'Staff berhasil ditambahkan.' });
|
|
} catch (error) {
|
|
console.error('POST /api/staff Error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// PUT /api/staff/:id - Update staff user
|
|
router.put('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { username, password, name, role, phone, assignedClasses, is_active } = req.body;
|
|
|
|
// Build dynamic update query
|
|
const updates = [];
|
|
const params = [];
|
|
|
|
if (username) {
|
|
updates.push('username = ?');
|
|
params.push(username);
|
|
}
|
|
if (password) {
|
|
updates.push('password = ?');
|
|
params.push(hashPassword(password));
|
|
}
|
|
if (name) {
|
|
updates.push('name = ?');
|
|
params.push(name);
|
|
}
|
|
if (role) {
|
|
updates.push('role = ?');
|
|
params.push(role);
|
|
}
|
|
if (typeof is_active === 'boolean') {
|
|
updates.push('is_active = ?');
|
|
params.push(is_active);
|
|
}
|
|
if (phone !== undefined) {
|
|
updates.push('phone = ?');
|
|
params.push(phone || null);
|
|
}
|
|
if (assignedClasses !== undefined) {
|
|
updates.push('assigned_classes = ?');
|
|
params.push(Array.isArray(assignedClasses) ? JSON.stringify(assignedClasses) : null);
|
|
}
|
|
|
|
if (updates.length === 0) {
|
|
return res.status(400).json({ error: 'Tidak ada data yang diubah.' });
|
|
}
|
|
|
|
params.push(id);
|
|
await pool.query(
|
|
`UPDATE staff_users SET ${updates.join(', ')} WHERE id = ?`,
|
|
params
|
|
);
|
|
|
|
res.json({ success: true, message: 'Staff berhasil diupdate.' });
|
|
} catch (error) {
|
|
console.error('PUT /api/staff Error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// DELETE /api/staff/:id - Delete staff user
|
|
router.delete('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
// Prevent deleting the last admin
|
|
const [admins] = await pool.query("SELECT COUNT(*) as count FROM staff_users WHERE role = 'ADMIN'");
|
|
const [targetUser] = await pool.query('SELECT role FROM staff_users WHERE id = ?', [id]);
|
|
|
|
if (targetUser.length > 0 && targetUser[0].role === 'ADMIN' && admins[0].count <= 1) {
|
|
return res.status(400).json({ error: 'Tidak dapat menghapus admin terakhir.' });
|
|
}
|
|
|
|
await pool.query('DELETE FROM staff_users WHERE id = ?', [id]);
|
|
|
|
res.json({ success: true, message: 'Staff berhasil dihapus.' });
|
|
} catch (error) {
|
|
console.error('DELETE /api/staff Error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
export default router;
|