diff --git a/.eslintrc.json b/.eslintrc.json index a0cbc54ccc..aac5302e02 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,13 +1,12 @@ { "env": { + "browser": true, "commonjs": true, - "es2021": true, - "node": true, - "jest": true + "es2021": true }, "extends": "eslint:recommended", "parserOptions": { - "ecmaVersion": "latest" + "ecmaVersion": 13 }, "rules": { } diff --git a/api/cars/cars-middleware.js b/api/cars/cars-middleware.js index 7e738d6062..97285d8059 100644 --- a/api/cars/cars-middleware.js +++ b/api/cars/cars-middleware.js @@ -1,15 +1,70 @@ -const checkCarId = (req, res, next) => { - // DO YOUR MAGIC +const Car = require('./cars-model') +const vin = require('vin-validator') + +const checkCarId = async (req, res, next) => { + try{ + const car = await Car.getById(req.params.id) + if(!car) { + next({status: 404, message: 'not found'}) + }else { + req.car = car + next() + } +} catch (error) { + next(error) +} } const checkCarPayload = (req, res, next) => { - // DO YOUR MAGIC + if(!req.body.vin) return next({ + status:400, + message: 'vin is missing' + }) + if(!req.body.make) return next({ + status:400, + message: 'make is missing' + }) + if(!req.body.model) return next({ + status:400, + message: 'model is missing' + }) + if(!req.body.mileage) return next({ + status:400, + message: 'mileage is missing' + }) + next() } -const checkVinNumberValid = (req, res, next) => { - // DO YOUR MAGIC +const checkVinNumberValid = async (req, res, next) => { + if(vin.validate(req.body.vin)){ + next() + }else{ + next({ + status: 400, + message: `vin ${req.body.vin} is invalid` + }) + } + } -const checkVinNumberUnique = (req, res, next) => { - // DO YOUR MAGIC +const checkVinNumberUnique = async (req, res, next) => { + try{ + const existing = await Cars.getByVin(req.body.vin) + if(!existing){ + next() + }else{ + next({ + status: 400, + message: `vin ${req.body.vin} already exists` + }) + } +}catch (err){ + next(err) +} } +module.exports = { + checkCarId, + checkCarPayload, + checkVinNumberUnique, + checkVinNumberValid, +} \ No newline at end of file diff --git a/api/cars/cars-model.js b/api/cars/cars-model.js index 39b2c50a8d..8591706345 100644 --- a/api/cars/cars-model.js +++ b/api/cars/cars-model.js @@ -1,11 +1,25 @@ +const db = require('../../data/db-config') + const getAll = () => { - // DO YOUR MAGIC + return db('cars') +} + +const getById = (id) => { + return db('cars').where('id', id).first() } -const getById = () => { - // DO YOUR MAGIC +const getByVin = (vin) => { + return db('cars').where('vin', vin).first() } const create = () => { - // DO YOUR MAGIC + return db('cars').insert(car).then(([id]) => { + return getById(id) + }) } +module.exports = { + getAll, + getById, + create, + getByVin, +} \ No newline at end of file diff --git a/api/cars/cars-router.js b/api/cars/cars-router.js index 3fca0e7d7d..af5fa38c6f 100644 --- a/api/cars/cars-router.js +++ b/api/cars/cars-router.js @@ -1 +1,44 @@ // DO YOUR MAGIC +const router = require('express').Router() +const Car = require('./cars-model') +const { + checkCarId, + checkCarPayload, + checkVinNumberUnique, + checkVinNumberValid, +} = require('./cars-middleware') + + +router.get('/', async (req, res, next) => { + try{ + const cars = await Car.getAll() + res.json(cars) + } catch (error) { + next(error) + } +}) + +router.get('/:id', checkCarId, async (req, res, next) => { + res.json(req.car) +}) + +router.post('/', +checkCarPayload, +checkVinNumberUnique, +checkVinNumberValid, +async (req, res, next) => { + try{ + const newCar = await Car.create(req.body) + res.status(201).json(newCar) + }catch (error) { + next(error) + } +}) + +router.use((err, req, res, next) => { + res.status(err.status || 500).json({ + message: err.message, + stack: err.stack, + }); + }); + module.exports = router \ No newline at end of file diff --git a/api/server.js b/api/server.js index c5a0be1b41..baac808363 100644 --- a/api/server.js +++ b/api/server.js @@ -1,7 +1,20 @@ const express = require("express") +const carsRouter = require('./cars/cars-router') const server = express() - // DO YOUR MAGIC +server.use(express.json()) +server.use('/api/cars', carsRouter) +server.use('*', (req, res, next) => { + next({ + status: 404, + message: 'not found' + }) +}) +server.use((err, req, res, next) => { // eslint-diable-line + res.status(err.status || 500).json({ + message: err.message + }) +}) module.exports = server diff --git a/data/dealer.db3 b/data/dealer.db3 new file mode 100644 index 0000000000..0ee10bfe73 Binary files /dev/null and b/data/dealer.db3 differ diff --git a/data/migrations/01-make_cars_table.js b/data/migrations/01-make_cars_table.js index 9723c175be..1bc4260371 100644 --- a/data/migrations/01-make_cars_table.js +++ b/data/migrations/01-make_cars_table.js @@ -1,7 +1,17 @@ exports.up = function (knex) { // DO YOUR MAGIC + return knex.schema.createTable('cars', (table) => { + table.increments() + table.string('vin', 16).notNullable().unique() + table.string('make', 128).notNullable() + table.string('model', 256).notNullable() + table.integer('mileage').unsigned().notNullable() + table.string('title', 128) + table.string('transmision', 128) + }) }; exports.down = function (knex) { // DO YOUR MAGIC + return knex.schema.dropTableIfExists('cars') }; diff --git a/data/seeds/01-cars.js b/data/seeds/01-cars.js index 3f7acdde23..26694c9bf1 100644 --- a/data/seeds/01-cars.js +++ b/data/seeds/01-cars.js @@ -1 +1,28 @@ -// STRETCH +const cars = [ + { + vin: 'JTEBU11F670058710', + make: 'toyota', + model: 'yaris', + mileage: 246000, + title: 'clean', + transmision: 'manual' + }, + { + vin: '1D7HA18287S191814', + make: 'jeep', + model: 'grand cherokee', + mileage: 115000, + title: 'clean', + }, + { + vin: '5UXXW3C58F0M65560', + make: 'ford', + model: 'bronco', + mileage: 250000, + } +] + +exports.seed = async function(knex){ + await knex('cars').truncate() + await knex('cars').insert(cars) +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bd99a1ccee..80757a50f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,12 +5,12 @@ "requires": true, "packages": { "": { - "name": "node-db2-project", "version": "1.0.0", "dependencies": { "express": "^4.17.1", "knex": "^0.95.11", - "sqlite3": "^5.0.2" + "sqlite3": "^5.0.2", + "vin-validator": "^1.0.0" }, "devDependencies": { "@types/jest": "^27.0.2", @@ -6912,6 +6912,11 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, + "node_modules/vin-validator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vin-validator/-/vin-validator-1.0.0.tgz", + "integrity": "sha1-F2Via4VYskAvd7bCXHYX9zzsrmc=" + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -12588,6 +12593,11 @@ } } }, + "vin-validator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vin-validator/-/vin-validator-1.0.0.tgz", + "integrity": "sha1-F2Via4VYskAvd7bCXHYX9zzsrmc=" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index e5d2cd615a..023b6f17ea 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,12 @@ "main": "index.js", "scripts": { "server": "nodemon index.js", - "test": "cross-env NODE_ENV=testing jest --verbose --runInBand" + "test": "cross-env NODE_ENV=testing jest --verbose --runInBand", + "migrate": "knex migrate:latest", + "rollback": "knex migrate:rollback", + "migup": "knex migrate:up", + "migdown": "knex migrate:down", + "seed": "knex seed:run" }, "devDependencies": { "@types/jest": "^27.0.2", @@ -17,7 +22,8 @@ "dependencies": { "express": "^4.17.1", "knex": "^0.95.11", - "sqlite3": "^5.0.2" + "sqlite3": "^5.0.2", + "vin-validator": "^1.0.0" }, "repository": { "type": "git",