working on healthcheck api and auth api (#2)
Reviewed-on: #2 Co-authored-by: Joseph Nelson <joseph.nelson4456@gmail.com> Co-committed-by: Joseph Nelson <joseph.nelson4456@gmail.com>
This commit was merged in pull request #2.
This commit is contained in:
+28
@@ -0,0 +1,28 @@
|
||||
import express from 'express'
|
||||
import path from 'path'
|
||||
import cors from 'cors'
|
||||
import healthCheckRoutes from './routes/healthcheck'
|
||||
import authRoutes from './routes/auth'
|
||||
|
||||
const app = express()
|
||||
const port = process.env.PORT || 3000
|
||||
|
||||
// Middleware
|
||||
app.use(express.json()) // For parsing application/json
|
||||
app.use(express.urlencoded({ extended: true })) // For parsing URL-encoded form data
|
||||
app.use(cors())
|
||||
|
||||
// Mount Routes
|
||||
app.use('/healthcheck', healthCheckRoutes)
|
||||
app.use('/auth', authRoutes)
|
||||
|
||||
// Default Route (Catch-all for undefined routes)
|
||||
app.use((req, res, next) => {
|
||||
res.status(404).send('Sorry, the resource you requested could not be found.')
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server listening on port ${port}`)
|
||||
})
|
||||
|
||||
export default app
|
||||
@@ -0,0 +1,10 @@
|
||||
// config/index.js
|
||||
export default {
|
||||
database: {
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
user: process.env.DB_USER || 'your_db_user',
|
||||
password: process.env.DB_PASSWORD || 'your_db_password',
|
||||
database: process.env.DB_NAME || 'your_db_name',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE images (
|
||||
id UUID PRIMARY KEY,
|
||||
file TEXT,
|
||||
image BYTEA,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE images;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE collections (
|
||||
id UUID PRIMARY KEY,
|
||||
name TEXT,
|
||||
image_id UUID,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (image_id) REFERENCES images(id)
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE collections;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE items (
|
||||
id UUID PRIMARY KEY,
|
||||
collection_id UUID,
|
||||
image_id UUID,
|
||||
productId TEXT,
|
||||
name TEXT,
|
||||
cleanName TEXT,
|
||||
extCardText TEXT,
|
||||
marketPrice TEXT,
|
||||
extRarity TEXT,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (collection_id) REFERENCES collections(id),
|
||||
FOREIGN KEY (image_id) REFERENCES images(id)
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE items;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE locations (
|
||||
id UUID PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE locations;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE sets (
|
||||
id UUID PRIMARY KEY,
|
||||
collection_id UUID NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
location_id UUID,
|
||||
image_id UUID,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (collection_id) REFERENCES collections(id),
|
||||
FOREIGN KEY (location_id) REFERENCES locations(id),
|
||||
FOREIGN KEY (image_id) REFERENCES images(id)
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE sets;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE roles (
|
||||
id UUID PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pmg) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE roles;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export const up = (pgm) => {
|
||||
pgm.sql(`
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
role_id UUID,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (role_id) REFERENCES roles(id)
|
||||
);
|
||||
`)
|
||||
}
|
||||
|
||||
export const down = (pgm) => {
|
||||
pgm.sql(`
|
||||
DROP TABLE users;
|
||||
`)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import express from 'express'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import { database } from '../../config'
|
||||
|
||||
const { Pool } = require('pg')
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
// Database connection pool
|
||||
const pool = new Pool(database)
|
||||
|
||||
// Route to handle login and issue JWT token
|
||||
router.post('/login', async (req, res) => {
|
||||
const { username, password } = req.body
|
||||
|
||||
try {
|
||||
const client = await pool.connect()
|
||||
const queryText = 'SELECT * FROM users WHERE username = $1'
|
||||
const result = await client.query(queryText, [username])
|
||||
|
||||
if (!result.rows.length) {
|
||||
return res.status(401).json({ message: 'Invalid credentials' })
|
||||
}
|
||||
|
||||
const user = result.rows[0]
|
||||
|
||||
// Compare passwords
|
||||
const passwordMatch = await bcrypt.compare(password, user.password)
|
||||
|
||||
if (!passwordMatch) {
|
||||
return res.status(401).json({ message: 'Invalid credentials' })
|
||||
}
|
||||
|
||||
// Issue JWT token
|
||||
const token = jwt.sign(
|
||||
{ id: user.id, username: user.username },
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: '1h' }
|
||||
)
|
||||
|
||||
res.json({ token })
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
res.status(500).json({ message: 'Internal server error' })
|
||||
}
|
||||
})
|
||||
|
||||
// Route to refresh JWT token
|
||||
router.post('/refresh-token', async (req, res) => {
|
||||
const { refreshToken } = req.body
|
||||
|
||||
if (!refreshToken) {
|
||||
return res.status(401).json({ message: 'Refresh token is required' })
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify the refresh token
|
||||
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET)
|
||||
|
||||
// Create a new access token (JWT)
|
||||
const token = jwt.sign(
|
||||
{ id: decoded.id, username: decoded.username },
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: '1h' }
|
||||
)
|
||||
|
||||
res.json({ token })
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
res.status(403).json({ message: 'Invalid refresh token' })
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,7 @@
|
||||
import express from 'express'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
router.get('/', (req, res) => res.json({ status: 'UP' }))
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,19 @@
|
||||
// src/routes/healthcheck/test.js
|
||||
|
||||
import request from 'supertest'
|
||||
import app from '../../app'
|
||||
|
||||
describe('Health Check Endpoint', () => {
|
||||
it('should respond with status up', async () => {
|
||||
const response = await request(app).get('/healthcheck')
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
expect(response.body).toEqual({ status: 'UP' })
|
||||
})
|
||||
|
||||
it('should return a JSON response', async () => {
|
||||
const response = await request(app).get('/healthcheck')
|
||||
|
||||
expect(response.type).toBe('application/json')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user