feat: Add initial identifier field to user management and update related functions

This commit is contained in:
2025-09-29 19:41:49 +02:00
parent fc5f0fd39a
commit e589d6667f
3 changed files with 34 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ export default function EditUserPage() {
username: "", username: "",
role: "user", role: "user",
is_active: true, is_active: true,
initial: "",
password: "" password: ""
}); });
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -65,6 +66,7 @@ export default function EditUserPage() {
username: userData.username, username: userData.username,
role: userData.role, role: userData.role,
is_active: userData.is_active, is_active: userData.is_active,
initial: userData.initial || "",
password: "" // Never populate password field password: "" // Never populate password field
}); });
} catch (err) { } catch (err) {
@@ -86,7 +88,8 @@ export default function EditUserPage() {
name: formData.name, name: formData.name,
username: formData.username, username: formData.username,
role: formData.role, role: formData.role,
is_active: formData.is_active is_active: formData.is_active,
initial: formData.initial.trim() || null
}; };
// Only include password if it's provided // Only include password if it's provided
@@ -253,6 +256,23 @@ export default function EditUserPage() {
</div> </div>
</div> </div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Initial
</label>
<Input
type="text"
value={formData.initial}
onChange={(e) => setFormData({ ...formData, initial: e.target.value })}
placeholder="1-2 letter identifier"
maxLength={2}
className="w-full md:w-1/2"
/>
<p className="text-xs text-gray-500 mt-1">
Optional 1-2 letter identifier for the user
</p>
</div>
<div className="flex items-center"> <div className="flex items-center">
<input <input
type="checkbox" type="checkbox"

View File

@@ -195,6 +195,9 @@ export default function UserManagementPage() {
<div> <div>
<h3 className="text-lg font-semibold text-gray-900">{user.name}</h3> <h3 className="text-lg font-semibold text-gray-900">{user.name}</h3>
<p className="text-sm text-gray-500">{user.username}</p> <p className="text-sm text-gray-500">{user.username}</p>
{user.initial && (
<p className="text-xs text-blue-600 font-medium mt-1">Initial: {user.initial}</p>
)}
</div> </div>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">

View File

@@ -19,7 +19,7 @@ export async function createUser({ name, username, password, role = 'user', is_a
return db.prepare(` return db.prepare(`
SELECT id, name, username, role, created_at, updated_at, last_login, SELECT id, name, username, role, created_at, updated_at, last_login,
is_active, failed_login_attempts, locked_until is_active, failed_login_attempts, locked_until, initial
FROM users WHERE id = ? FROM users WHERE id = ?
`).get(userId) `).get(userId)
} }
@@ -28,7 +28,7 @@ export async function createUser({ name, username, password, role = 'user', is_a
export function getUserById(id) { export function getUserById(id) {
return db.prepare(` return db.prepare(`
SELECT id, name, username, password_hash, role, created_at, updated_at, last_login, SELECT id, name, username, password_hash, role, created_at, updated_at, last_login,
is_active, failed_login_attempts, locked_until is_active, failed_login_attempts, locked_until, initial
FROM users WHERE id = ? FROM users WHERE id = ?
`).get(id) `).get(id)
} }
@@ -36,7 +36,7 @@ export function getUserById(id) {
// Get user by username // Get user by username
export function getUserByUsername(username) { export function getUserByUsername(username) {
return db.prepare(` return db.prepare(`
SELECT id, name, username, role, created_at, last_login, is_active SELECT id, name, username, role, created_at, last_login, is_active, initial
FROM users WHERE username = ? FROM users WHERE username = ?
`).get(username) `).get(username)
} }
@@ -45,7 +45,7 @@ export function getUserByUsername(username) {
export function getAllUsers() { export function getAllUsers() {
return db.prepare(` return db.prepare(`
SELECT id, name, username, password_hash, role, created_at, updated_at, last_login, is_active, SELECT id, name, username, password_hash, role, created_at, updated_at, last_login, is_active,
failed_login_attempts, locked_until failed_login_attempts, locked_until, initial
FROM users FROM users
ORDER BY created_at DESC ORDER BY created_at DESC
`).all() `).all()
@@ -172,6 +172,11 @@ export async function updateUser(userId, updates) {
updateValues.push(updates.is_active ? 1 : 0); updateValues.push(updates.is_active ? 1 : 0);
} }
if (updates.initial !== undefined) {
updateFields.push("initial = ?");
updateValues.push(updates.initial);
}
if (updates.password !== undefined) { if (updates.password !== undefined) {
const passwordHash = await bcrypt.hash(updates.password, 12); const passwordHash = await bcrypt.hash(updates.password, 12);
updateFields.push("password_hash = ?"); updateFields.push("password_hash = ?");
@@ -199,7 +204,7 @@ export async function updateUser(userId, updates) {
if (result.changes > 0) { if (result.changes > 0) {
return db.prepare(` return db.prepare(`
SELECT id, name, username, role, created_at, updated_at, last_login, SELECT id, name, username, role, created_at, updated_at, last_login,
is_active, failed_login_attempts, locked_until is_active, failed_login_attempts, locked_until, initial
FROM users WHERE id = ? FROM users WHERE id = ?
`).get(userId); `).get(userId);
} }