feat: Implement user tracking in projects

- Added user tracking features to the projects module, including:
  - Database schema updates to track project creator and assignee.
  - API enhancements for user management and project filtering by user.
  - UI components for user assignment in project forms and listings.
  - New query functions for retrieving users and filtering projects.
  - Security integration with role-based access and authentication requirements.

chore: Create utility scripts for database checks and project testing

- Added scripts to check the structure of the projects table.
- Created tests for project creation and user tracking functionality.
- Implemented API tests to verify project retrieval and user assignment.

fix: Update project creation and update functions to include user tracking

- Modified createProject and updateProject functions to handle user IDs for creator and assignee.
- Ensured that project updates reflect the correct user assignments and timestamps.
This commit is contained in:
Chop
2025-06-25 23:08:15 +02:00
parent 81afa09f3a
commit 294d8343d3
19 changed files with 790 additions and 35 deletions

View File

@@ -1,21 +1,48 @@
import db from "../db.js";
export function getAllProjects(contractId = null) {
const baseQuery = `
SELECT
p.*,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM projects p
LEFT JOIN users creator ON p.created_by = creator.id
LEFT JOIN users assignee ON p.assigned_to = assignee.id
`;
if (contractId) {
return db
.prepare(
"SELECT * FROM projects WHERE contract_id = ? ORDER BY finish_date DESC"
baseQuery + " WHERE p.contract_id = ? ORDER BY p.finish_date DESC"
)
.all(contractId);
}
return db.prepare("SELECT * FROM projects ORDER BY finish_date DESC").all();
return db.prepare(baseQuery + " ORDER BY p.finish_date DESC").all();
}
export function getProjectById(id) {
return db.prepare("SELECT * FROM projects WHERE project_id = ?").get(id);
return db
.prepare(
`
SELECT
p.*,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM projects p
LEFT JOIN users creator ON p.created_by = creator.id
LEFT JOIN users assignee ON p.assigned_to = assignee.id
WHERE p.project_id = ?
`
)
.get(id);
}
export function createProject(data) {
export function createProject(data, userId = null) {
// 1. Get the contract number and count existing projects
const contractInfo = db
.prepare(
@@ -37,12 +64,16 @@ export function createProject(data) {
// 2. Generate sequential number and project number
const sequentialNumber = (contractInfo.project_count || 0) + 1;
const projectNumber = `${sequentialNumber}/${contractInfo.contract_number}`; const stmt = db.prepare(`
const projectNumber = `${sequentialNumber}/${contractInfo.contract_number}`;
const stmt = db.prepare(`
INSERT INTO projects (
contract_id, project_name, project_number, address, plot, district, unit, city, investment_number, finish_date,
wp, contact, notes, project_type, project_status, coordinates
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);stmt.run(
wp, contact, notes, project_type, project_status, coordinates, created_by, assigned_to, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
`);
const result = stmt.run(
data.contract_id,
data.project_name,
projectNumber,
@@ -55,16 +86,23 @@ export function createProject(data) {
data.finish_date,
data.wp,
data.contact,
data.notes, data.project_type || "design",
data.notes,
data.project_type || "design",
data.project_status || "registered",
data.coordinates || null
data.coordinates || null,
userId,
data.assigned_to || null
);
return result;
}
export function updateProject(id, data) { const stmt = db.prepare(`
export function updateProject(id, data, userId = null) {
const stmt = db.prepare(`
UPDATE projects SET
contract_id = ?, project_name = ?, project_number = ?, address = ?, plot = ?, district = ?, unit = ?, city = ?,
investment_number = ?, finish_date = ?, wp = ?, contact = ?, notes = ?, project_type = ?, project_status = ?, coordinates = ?
investment_number = ?, finish_date = ?, wp = ?, contact = ?, notes = ?, project_type = ?, project_status = ?,
coordinates = ?, assigned_to = ?, updated_at = CURRENT_TIMESTAMP
WHERE project_id = ?
`);
stmt.run(
@@ -80,9 +118,11 @@ export function updateProject(id, data) { const stmt = db.prepare(`
data.finish_date,
data.wp,
data.contact,
data.notes, data.project_type || "design",
data.notes,
data.project_type || "design",
data.project_status || "registered",
data.coordinates || null,
data.assigned_to || null,
id
);
}
@@ -91,6 +131,75 @@ export function deleteProject(id) {
db.prepare("DELETE FROM projects WHERE project_id = ?").run(id);
}
// Get all users for assignment dropdown
export function getAllUsersForAssignment() {
return db
.prepare(
`
SELECT id, name, email, role
FROM users
WHERE is_active = 1
ORDER BY name
`
)
.all();
}
// Get projects assigned to a specific user
export function getProjectsByAssignedUser(userId) {
return db
.prepare(
`
SELECT
p.*,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM projects p
LEFT JOIN users creator ON p.created_by = creator.id
LEFT JOIN users assignee ON p.assigned_to = assignee.id
WHERE p.assigned_to = ?
ORDER BY p.finish_date DESC
`
)
.all(userId);
}
// Get projects created by a specific user
export function getProjectsByCreator(userId) {
return db
.prepare(
`
SELECT
p.*,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM projects p
LEFT JOIN users creator ON p.created_by = creator.id
LEFT JOIN users assignee ON p.assigned_to = assignee.id
WHERE p.created_by = ?
ORDER BY p.finish_date DESC
`
)
.all(userId);
}
// Update project assignment
export function updateProjectAssignment(projectId, assignedToUserId) {
return db
.prepare(
`
UPDATE projects
SET assigned_to = ?, updated_at = CURRENT_TIMESTAMP
WHERE project_id = ?
`
)
.run(assignedToUserId, projectId);
}
export function getProjectWithContract(id) {
return db
.prepare(