104 lines
3.6 KiB
JavaScript
104 lines
3.6 KiB
JavaScript
const express = require('express');
|
|
const sqlite3 = require('better-sqlite3');
|
|
const cors = require('cors');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const app = express();
|
|
const PORT = 3000;
|
|
const DB_PATH = '/opt/project-tracker/data/projects.db';
|
|
const DATA_DIR = '/opt/project-tracker/data';
|
|
|
|
// Ensure data directory exists
|
|
if (!fs.existsSync(DATA_DIR)) {
|
|
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
}
|
|
|
|
// Initialize database
|
|
const db = new sqlite3(DB_PATH);
|
|
|
|
// Create table
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS projects (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
priority TEXT NOT NULL,
|
|
url TEXT DEFAULT '',
|
|
notes TEXT DEFAULT '',
|
|
status TEXT DEFAULT 'Backlog',
|
|
owner TEXT DEFAULT 'Ada',
|
|
tags TEXT DEFAULT '',
|
|
created_at TEXT DEFAULT (datetime('now')),
|
|
updated_at TEXT DEFAULT (datetime('now'))
|
|
)
|
|
`);
|
|
|
|
// Middleware
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
// GET all projects
|
|
app.get('/api/projects', (req, res) => {
|
|
const { status } = req.query;
|
|
let stmt = status
|
|
? db.prepare('SELECT * FROM projects WHERE status = ? ORDER BY CASE priority WHEN \'High\' THEN 1 WHEN \'Med-High\' THEN 2 WHEN \'Medium\' THEN 3 WHEN \'Low\' THEN 4 ELSE 5 END, created_at DESC')
|
|
: db.prepare('SELECT * FROM projects ORDER BY CASE priority WHEN \'High\' THEN 1 WHEN \'Med-High\' THEN 2 WHEN \'Medium\' THEN 3 WHEN \'Low\' THEN 4 ELSE 5 END, created_at DESC');
|
|
const rows = status ? stmt.all(status) : stmt.all();
|
|
res.json(rows);
|
|
});
|
|
|
|
// GET single project
|
|
app.get('/api/projects/:id', (req, res) => {
|
|
const stmt = db.prepare('SELECT * FROM projects WHERE id = ?');
|
|
const row = stmt.get(req.params.id);
|
|
if (row) res.json(row);
|
|
else res.status(404).json({ error: 'Not found' });
|
|
});
|
|
|
|
// POST create project
|
|
app.post('/api/projects', (req, res) => {
|
|
const { name, priority, url, notes, status, owner, tags } = req.body;
|
|
if (!name || !priority) {
|
|
return res.status(400).json({ error: 'name and priority are required' });
|
|
}
|
|
const stmt = db.prepare(`
|
|
INSERT INTO projects (name, priority, url, notes, status, owner, tags)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
`);
|
|
const result = stmt.run(name, priority, url || '', notes || '', status || 'Backlog', owner || 'Ada', tags || '');
|
|
res.json({ id: result.lastInsertRowid, message: 'Created' });
|
|
});
|
|
|
|
// PUT update project
|
|
app.put('/api/projects/:id', (req, res) => {
|
|
const { name, priority, url, notes, status, owner, tags } = req.body;
|
|
const fields = [];
|
|
const values = [];
|
|
if (name !== undefined) { fields.push('name = ?'); values.push(name); }
|
|
if (priority !== undefined) { fields.push('priority = ?'); values.push(priority); }
|
|
if (url !== undefined) { fields.push('url = ?'); values.push(url); }
|
|
if (notes !== undefined) { fields.push('notes = ?'); values.push(notes); }
|
|
if (status !== undefined) { fields.push('status = ?'); values.push(status); }
|
|
if (owner !== undefined) { fields.push('owner = ?'); values.push(owner); }
|
|
if (tags !== undefined) { fields.push('tags = ?'); values.push(tags); }
|
|
fields.push('updated_at = datetime(\'now\')');
|
|
values.push(req.params.id);
|
|
if (fields.length === 1) {
|
|
return res.status(400).json({ error: 'No fields to update' });
|
|
}
|
|
const stmt = db.prepare(`UPDATE projects SET ${fields.join(', ')} WHERE id = ?`);
|
|
stmt.run(...values);
|
|
res.json({ message: 'Updated' });
|
|
});
|
|
|
|
// DELETE project
|
|
app.delete('/api/projects/:id', (req, res) => {
|
|
const stmt = db.prepare('DELETE FROM projects WHERE id = ?');
|
|
stmt.run(req.params.id);
|
|
res.json({ message: 'Deleted' });
|
|
});
|
|
|
|
app.listen(PORT, '0.0.0.0', () => {
|
|
console.log(`Project Tracker API running on port ${PORT}`);
|
|
});
|