From f3a7fe6cbe591587f5e1202ded3f4e85ddc2af66 Mon Sep 17 00:00:00 2001 From: Joseph Nelson Date: Sat, 16 May 2026 22:30:54 -0700 Subject: [PATCH 1/3] added image and location APIs --- package.json | 1 + src/app.js | 4 ++ src/routes/images/index.js | 113 ++++++++++++++++++++++++++++++++++ src/routes/locations/index.js | 91 +++++++++++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 src/routes/images/index.js create mode 100644 src/routes/locations/index.js diff --git a/package.json b/package.json index 9b0c7fa..9a590be 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "csv-parser": "^3.0.0", "dotenv": "^16.0.3", "express": "^4.22.2", + "express-validator": "^7.3.2", "jsonwebtoken": "^9.0.3", "node-pg": "^1.0.1", "p-limit": "^7.3.0", diff --git a/src/app.js b/src/app.js index c62d529..598f2a8 100644 --- a/src/app.js +++ b/src/app.js @@ -5,6 +5,8 @@ import healthCheckRoutes from './routes/healthcheck' import authRoutes from './routes/auth' import userRoutes from './routes/users' import roleRoutes from './routes/roles' +import locationRoutes from './routes/locations' +import imageRoutes from './routes/images' const app = express() const port = process.env.PORT || 3000 @@ -19,6 +21,8 @@ app.use('/healthcheck', healthCheckRoutes) app.use('/auth', authRoutes) app.use('/users', userRoutes) app.use('/roles', roleRoutes) +app.use('/locations', locationRoutes) +app.use('/images', imageRoutes) // Default Route (Catch-all for undefined routes) app.use((req, res, next) => { diff --git a/src/routes/images/index.js b/src/routes/images/index.js new file mode 100644 index 0000000..a0b59d5 --- /dev/null +++ b/src/routes/images/index.js @@ -0,0 +1,113 @@ +import express from 'express' +import { check, validationResult } from 'express-validator/check' +import { Pool } from 'pg' +import { database } from '../../config' + +const router = express.Router() + +// Create a connection pool to the database +const pool = new Pool(database) + +// CREATE AN IMAGE +router.post('/', [ + check('file').isString(), + check('image').isBase64() +], async (req, res) => { + try { + const errors = validationResult(req) + if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }) + + const { file, image } = req.body + + const client = await pool.connect() + const result = await client.query('INSERT INTO images (file, image, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) RETURNING *', [file, image]) + client.release() + + return res.status(201).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } +}) + +// READ AN IMAGE +router.get('/:id', async (req, res) => { + try { + const { id } = req.params + + const client = await pool.connect() + const result = await client.query('SELECT * FROM images WHERE id = $1', [id]) + client.release() + + if (result.rows.length === 0) return res.status(404).json({ error: 'Image not found' }) + + return res.status(200).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } +}) + +// UPDATE AN IMAGE +router.put('/:id', [ + check('file').optional().isString(), + check('image').optional().isBase64() +], async (req, res) => { + try { + const errors = validationResult(req) + if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }) + + const { id } = req.params + const { file, image } = req.body + + const client = await pool.connect() + let query = 'UPDATE images SET' + const values = [] + + if (file) { + query += ' file = $1,' + values.push(file) + } + + if (image) { + query += ' image = $2,' + values.push(image) + } + + // Remove trailing comma and space from query string + query = query.slice(0, -1) + + query += ', updated_at = NOW() WHERE id = $3 RETURNING *' + values.push(id) + + const result = await client.query(query, values) + client.release() + + if (result.rows.length === 0) return res.status(404).json({ error: 'Image not found' }) + + return res.status(200).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } +}) + +// DELETE AN IMAGE +router.delete('/:id', async (req, res) => { + try { + const { id } = req.params + + const client = await pool.connect() + const result = await client.query('DELETE FROM images WHERE id = $1 RETURNING *', [id]) + client.release() + + if (result.rows.length === 0) return res.status(404).json({ error: 'Image not found' }) + + return res.status(200).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } +}) + +export default router diff --git a/src/routes/locations/index.js b/src/routes/locations/index.js new file mode 100644 index 0000000..774f668 --- /dev/null +++ b/src/routes/locations/index.js @@ -0,0 +1,91 @@ +import express from 'express' +import { check, validationResult } from 'express-validator/check' +import { Pool } from 'pg' +import { database } from '../../config' + +const router = express.Router() + +// Create a connection pool to the database +const pool = new Pool(database) + +// Create a new location +router.post( + '/', + [check('name', 'Name is required').not().isEmpty()], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + try { + const { name } = req.body + await pool.query( + 'INSERT INTO locations (name, created_at, updated_at) VALUES ($1, NOW(), NOW())', + [name] + ) + res.send({ message: 'Location created' }) + } catch (err) { + console.error(err.message) + res.status(500).send('Server error') + } + } +) + +// Get all locations +router.get('/', async (req, res) => { + try { + const result = await pool.query('SELECT * FROM locations') + res.send(result.rows) + } catch (err) { + console.error(err.message) + res.status(500).send('Server error') + } +}) + +// Get a single location by ID +router.get('/:id', async (req, res) => { + try { + const result = await pool.query('SELECT * FROM locations WHERE id = $1', [req.params.id]) + if (result.rows.length === 0) return res.status(404).send('Location not found') + res.send(result.rows[0]) + } catch (err) { + console.error(err.message) + res.status(500).send('Server error') + } +}) + +// Update a location +router.put( + '/:id', + [check('name', 'Name is required').not().isEmpty()], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + try { + const { name } = req.body + await pool.query( + 'UPDATE locations SET name = $1, updated_at = NOW() WHERE id = $2', + [name, req.params.id] + ) + res.send({ message: 'Location updated' }) + } catch (err) { + console.error(err.message) + res.status(500).send('Server error') + } + } +) + +// Delete a location +router.delete('/:id', async (req, res) => { + try { + await pool.query('DELETE FROM locations WHERE id = $1', [req.params.id]) + res.send({ message: 'Location deleted' }) + } catch (err) { + console.error(err.message) + res.status(500).send('Server error') + } +}) + +export default router -- 2.52.0 From 2b921b697e934af03971ea2fab0778454d87aab6 Mon Sep 17 00:00:00 2001 From: Joseph Nelson Date: Sat, 16 May 2026 22:33:48 -0700 Subject: [PATCH 2/3] fixed linting issue --- src/routes/images/index.js | 162 +++++++++++++++++++--------------- src/routes/locations/index.js | 10 ++- 2 files changed, 96 insertions(+), 76 deletions(-) diff --git a/src/routes/images/index.js b/src/routes/images/index.js index a0b59d5..7573c44 100644 --- a/src/routes/images/index.js +++ b/src/routes/images/index.js @@ -1,113 +1,129 @@ import express from 'express' -import { check, validationResult } from 'express-validator/check' import { Pool } from 'pg' import { database } from '../../config' +const { check, validationResult } = require('express-validator/check') + const router = express.Router() // Create a connection pool to the database const pool = new Pool(database) // CREATE AN IMAGE -router.post('/', [ - check('file').isString(), - check('image').isBase64() -], async (req, res) => { - try { - const errors = validationResult(req) - if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }) +router.post( + '/', + [check('file').isString(), check('image').isBase64()], + async (req, res) => { + try { + const errors = validationResult(req) + if (!errors.isEmpty()) + return res.status(400).json({ errors: errors.array() }) - const { file, image } = req.body + const { file, image } = req.body - const client = await pool.connect() - const result = await client.query('INSERT INTO images (file, image, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) RETURNING *', [file, image]) - client.release() + const client = await pool.connect() + const result = await client.query( + 'INSERT INTO images (file, image, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) RETURNING *', + [file, image] + ) + client.release() - return res.status(201).json(result.rows[0]) - } catch (err) { - console.error(err.stack) - return res.status(500).json({ error: 'Server error' }) - } -}) + return res.status(201).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } + } +) // READ AN IMAGE router.get('/:id', async (req, res) => { - try { - const { id } = req.params + try { + const { id } = req.params - const client = await pool.connect() - const result = await client.query('SELECT * FROM images WHERE id = $1', [id]) - client.release() + const client = await pool.connect() + const result = await client.query('SELECT * FROM images WHERE id = $1', [ + id, + ]) + client.release() - if (result.rows.length === 0) return res.status(404).json({ error: 'Image not found' }) + if (result.rows.length === 0) + return res.status(404).json({ error: 'Image not found' }) - return res.status(200).json(result.rows[0]) - } catch (err) { - console.error(err.stack) - return res.status(500).json({ error: 'Server error' }) - } + return res.status(200).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } }) // UPDATE AN IMAGE -router.put('/:id', [ - check('file').optional().isString(), - check('image').optional().isBase64() -], async (req, res) => { - try { - const errors = validationResult(req) - if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }) +router.put( + '/:id', + [check('file').optional().isString(), check('image').optional().isBase64()], + async (req, res) => { + try { + const errors = validationResult(req) + if (!errors.isEmpty()) + return res.status(400).json({ errors: errors.array() }) - const { id } = req.params - const { file, image } = req.body + const { id } = req.params + const { file, image } = req.body - const client = await pool.connect() - let query = 'UPDATE images SET' - const values = [] + const client = await pool.connect() + let query = 'UPDATE images SET' + const values = [] - if (file) { - query += ' file = $1,' - values.push(file) - } + if (file) { + query += ' file = $1,' + values.push(file) + } - if (image) { - query += ' image = $2,' - values.push(image) - } + if (image) { + query += ' image = $2,' + values.push(image) + } - // Remove trailing comma and space from query string - query = query.slice(0, -1) + // Remove trailing comma and space from query string + query = query.slice(0, -1) - query += ', updated_at = NOW() WHERE id = $3 RETURNING *' - values.push(id) + query += ', updated_at = NOW() WHERE id = $3 RETURNING *' + values.push(id) - const result = await client.query(query, values) - client.release() + const result = await client.query(query, values) + client.release() - if (result.rows.length === 0) return res.status(404).json({ error: 'Image not found' }) + if (result.rows.length === 0) + return res.status(404).json({ error: 'Image not found' }) - return res.status(200).json(result.rows[0]) - } catch (err) { - console.error(err.stack) - return res.status(500).json({ error: 'Server error' }) - } -}) + return res.status(200).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } + } +) // DELETE AN IMAGE router.delete('/:id', async (req, res) => { - try { - const { id } = req.params + try { + const { id } = req.params - const client = await pool.connect() - const result = await client.query('DELETE FROM images WHERE id = $1 RETURNING *', [id]) - client.release() + const client = await pool.connect() + const result = await client.query( + 'DELETE FROM images WHERE id = $1 RETURNING *', + [id] + ) + client.release() - if (result.rows.length === 0) return res.status(404).json({ error: 'Image not found' }) + if (result.rows.length === 0) + return res.status(404).json({ error: 'Image not found' }) - return res.status(200).json(result.rows[0]) - } catch (err) { - console.error(err.stack) - return res.status(500).json({ error: 'Server error' }) - } + return res.status(200).json(result.rows[0]) + } catch (err) { + console.error(err.stack) + return res.status(500).json({ error: 'Server error' }) + } }) export default router diff --git a/src/routes/locations/index.js b/src/routes/locations/index.js index 774f668..0baa08c 100644 --- a/src/routes/locations/index.js +++ b/src/routes/locations/index.js @@ -1,8 +1,9 @@ import express from 'express' -import { check, validationResult } from 'express-validator/check' import { Pool } from 'pg' import { database } from '../../config' +const { check, validationResult } = require('express-validator/check') + const router = express.Router() // Create a connection pool to the database @@ -45,8 +46,11 @@ router.get('/', async (req, res) => { // Get a single location by ID router.get('/:id', async (req, res) => { try { - const result = await pool.query('SELECT * FROM locations WHERE id = $1', [req.params.id]) - if (result.rows.length === 0) return res.status(404).send('Location not found') + const result = await pool.query('SELECT * FROM locations WHERE id = $1', [ + req.params.id, + ]) + if (result.rows.length === 0) + return res.status(404).send('Location not found') res.send(result.rows[0]) } catch (err) { console.error(err.message) -- 2.52.0 From 92e5cbe7117990ddad7d50845b34ef5bde8132c0 Mon Sep 17 00:00:00 2001 From: Joseph Nelson Date: Sat, 16 May 2026 22:39:42 -0700 Subject: [PATCH 3/3] fixed import issue --- src/routes/images/index.js | 2 +- src/routes/locations/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/images/index.js b/src/routes/images/index.js index 7573c44..4439ba7 100644 --- a/src/routes/images/index.js +++ b/src/routes/images/index.js @@ -2,7 +2,7 @@ import express from 'express' import { Pool } from 'pg' import { database } from '../../config' -const { check, validationResult } = require('express-validator/check') +const { check, validationResult } = require('express-validator') const router = express.Router() diff --git a/src/routes/locations/index.js b/src/routes/locations/index.js index 0baa08c..2fd32ac 100644 --- a/src/routes/locations/index.js +++ b/src/routes/locations/index.js @@ -2,7 +2,7 @@ import express from 'express' import { Pool } from 'pg' import { database } from '../../config' -const { check, validationResult } = require('express-validator/check') +const { check, validationResult } = require('express-validator') const router = express.Router() -- 2.52.0