diff --git a/server.js b/server.js index 8a16906..c49853e 100644 --- a/server.js +++ b/server.js @@ -15,6 +15,7 @@ for (const [name, value] of Object.entries({ APP_BASE_URL, ISSUER, CLIENT_ID, CL const pool = new Pool({ connectionString: DATABASE_URL, max: 5 }); const sessions = new Map(); +const PRIORITIES = new Set(['low', 'normal', 'high']); function esc(value) { return String(value ?? '').replace(/[&<>"']/g, ch => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[ch]); @@ -66,14 +67,23 @@ function sessionFor(req) { return session; } +function normalisePriority(value) { + const priority = String(value || 'normal').toLowerCase(); + return PRIORITIES.has(priority) ? priority : 'normal'; +} + +function priorityOptions(current = 'normal') { + return ['low', 'normal', 'high'].map(value => ``).join(''); +} + function layout(user, content) { return ` Arrowstack Tasks
-

Arrowstack Tasks

Keycloak + dedicated PostgreSQL CRUD demo
${esc(user.preferred_username || user.email || 'user')}   Logout
+

Arrowstack Tasks schema v2

Keycloak + dedicated PostgreSQL CRUD demo
${esc(user.preferred_username || user.email || 'user')}   Logout
${content}
`; } @@ -84,24 +94,33 @@ async function initDb() { id BIGSERIAL PRIMARY KEY, title TEXT NOT NULL CHECK (char_length(title) BETWEEN 1 AND 200), completed BOOLEAN NOT NULL DEFAULT FALSE, + priority TEXT NOT NULL DEFAULT 'normal' CHECK (priority IN ('low', 'normal', 'high')), created_by TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) `); + + await pool.query(` + ALTER TABLE tasks + ADD COLUMN IF NOT EXISTS priority TEXT NOT NULL DEFAULT 'normal' + CHECK (priority IN ('low', 'normal', 'high')) + `); + await pool.query(`CREATE INDEX IF NOT EXISTS idx_tasks_created_by_created_at ON tasks (created_by, created_at DESC)`); + await pool.query(`CREATE INDEX IF NOT EXISTS idx_tasks_created_by_priority_created_at ON tasks (created_by, priority, created_at DESC)`); } await initDb(); -console.log('database schema ready'); +console.log('database schema v2 ready'); const server = http.createServer(async (req, res) => { try { const url = new URL(req.url, APP_BASE_URL); if (url.pathname === '/health') { - await pool.query('SELECT 1'); - return send(res, 200, JSON.stringify({ ok: true, database: 'connected' }), 'application/json; charset=utf-8'); + await pool.query('SELECT priority FROM tasks LIMIT 1'); + return send(res, 200, JSON.stringify({ ok: true, database: 'connected', schema: 2 }), 'application/json; charset=utf-8'); } if (url.pathname === '/login') { @@ -161,7 +180,8 @@ const server = http.createServer(async (req, res) => { if (req.method === 'POST' && url.pathname === '/tasks') { const form = await readForm(req); const title = String(form.title || '').trim().slice(0, 200); - if (title) await pool.query('INSERT INTO tasks (title, created_by) VALUES ($1, $2)', [title, userKey]); + const priority = normalisePriority(form.priority); + if (title) await pool.query('INSERT INTO tasks (title, priority, created_by) VALUES ($1, $2, $3)', [title, priority, userKey]); return redirect(res, '/'); } @@ -174,7 +194,8 @@ const server = http.createServer(async (req, res) => { } else if (action === 'update') { const form = await readForm(req); const title = String(form.title || '').trim().slice(0, 200); - if (title) await pool.query('UPDATE tasks SET title = $1, updated_at = NOW() WHERE id = $2 AND created_by = $3', [title, id, userKey]); + const priority = normalisePriority(form.priority); + if (title) await pool.query('UPDATE tasks SET title = $1, priority = $2, updated_at = NOW() WHERE id = $3 AND created_by = $4', [title, priority, id, userKey]); } else if (action === 'delete') { await pool.query('DELETE FROM tasks WHERE id = $1 AND created_by = $2', [id, userKey]); } @@ -182,15 +203,15 @@ const server = http.createServer(async (req, res) => { } if (req.method === 'GET' && url.pathname === '/') { - const result = await pool.query('SELECT id, title, completed, created_at FROM tasks WHERE created_by = $1 ORDER BY created_at DESC', [userKey]); + const result = await pool.query('SELECT id, title, completed, priority, created_at FROM tasks WHERE created_by = $1 ORDER BY created_at DESC', [userKey]); const rows = result.rows.map(task => `
-
Created ${esc(new Date(task.created_at).toLocaleString())}
+
${esc(task.priority)}
Created ${esc(new Date(task.created_at).toLocaleString())}
`).join(''); - return send(res, 200, layout(session.user, `
${rows || '
No tasks yet. Add one above.
'}
`)); + return send(res, 200, layout(session.user, `
${rows || '
No tasks yet. Add one above.
'}
`)); } return send(res, 404, 'Not found', 'text/plain; charset=utf-8');