-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4259409
Showing
36 changed files
with
5,792 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
"use strict"; | ||
|
||
/** Express app for jobly. */ | ||
|
||
const express = require("express"); | ||
const cors = require("cors"); | ||
|
||
const { NotFoundError } = require("./expressError"); | ||
|
||
const { authenticateJWT } = require("./middleware/auth"); | ||
const authRoutes = require("./routes/auth"); | ||
const companiesRoutes = require("./routes/companies"); | ||
const usersRoutes = require("./routes/users"); | ||
|
||
const morgan = require("morgan"); | ||
|
||
const app = express(); | ||
|
||
app.use(cors()); | ||
app.use(express.json()); | ||
app.use(morgan("tiny")); | ||
app.use(authenticateJWT); | ||
|
||
app.use("/auth", authRoutes); | ||
app.use("/companies", companiesRoutes); | ||
app.use("/users", usersRoutes); | ||
|
||
|
||
/** Handle 404 errors -- this matches everything */ | ||
app.use(function (req, res, next) { | ||
return next(new NotFoundError()); | ||
}); | ||
|
||
/** Generic error handler; anything unhandled goes here. */ | ||
app.use(function (err, req, res, next) { | ||
if (process.env.NODE_ENV !== "test") console.error(err.stack); | ||
const status = err.status || 500; | ||
const message = err.message; | ||
|
||
return res.status(status).json({ | ||
error: { message, status }, | ||
}); | ||
}); | ||
|
||
module.exports = app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const request = require("supertest"); | ||
|
||
const app = require("./app"); | ||
const db = require("./db"); | ||
|
||
|
||
test("not found for site 404", async function () { | ||
const resp = await request(app).get("/no-such-path"); | ||
expect(resp.statusCode).toEqual(404); | ||
}); | ||
|
||
test("not found for site 404 (test stack print)", async function () { | ||
process.env.NODE_ENV = ""; | ||
const resp = await request(app).get("/no-such-path"); | ||
expect(resp.statusCode).toEqual(404); | ||
delete process.env.NODE_ENV; | ||
}); | ||
|
||
afterAll(function () { | ||
db.end(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"use strict"; | ||
|
||
/** Shared config for application; can be required many places. */ | ||
|
||
require("dotenv").config(); | ||
require("colors"); | ||
|
||
const SECRET_KEY = process.env.SECRET_KEY || "secret-dev"; | ||
|
||
const PORT = +process.env.PORT || 3001; | ||
|
||
// Use dev database, testing database, or via env var, production database | ||
function getDatabaseUri() { | ||
return (process.env.NODE_ENV === "test") | ||
? "postgresql:///jobly_test" | ||
: process.env.DATABASE_URL || "postgresql:///jobly"; | ||
} | ||
|
||
// Speed up bcrypt during tests, since the algorithm safety isn't being tested | ||
// | ||
// WJB: Evaluate in 2021 if this should be increased to 13 for non-test use | ||
const BCRYPT_WORK_FACTOR = process.env.NODE_ENV === "test" ? 1 : 12; | ||
|
||
console.log("Jobly Config:".green); | ||
console.log("SECRET_KEY:".yellow, SECRET_KEY); | ||
console.log("PORT:".yellow, PORT.toString()); | ||
console.log("BCRYPT_WORK_FACTOR".yellow, BCRYPT_WORK_FACTOR); | ||
console.log("Database:".yellow, getDatabaseUri()); | ||
console.log("---"); | ||
|
||
module.exports = { | ||
SECRET_KEY, | ||
PORT, | ||
BCRYPT_WORK_FACTOR, | ||
getDatabaseUri, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
"use strict"; | ||
|
||
describe("config can come from env", function () { | ||
test("works", function() { | ||
process.env.SECRET_KEY = "abc"; | ||
process.env.PORT = "5000"; | ||
process.env.DATABASE_URL = "other"; | ||
process.env.NODE_ENV = "other"; | ||
|
||
const config = require("./config"); | ||
expect(config.SECRET_KEY).toEqual("abc"); | ||
expect(config.PORT).toEqual(5000); | ||
expect(config.getDatabaseUri()).toEqual("other"); | ||
expect(config.BCRYPT_WORK_FACTOR).toEqual(12); | ||
|
||
delete process.env.SECRET_KEY; | ||
delete process.env.PORT; | ||
delete process.env.BCRYPT_WORK_FACTOR; | ||
delete process.env.DATABASE_URL; | ||
|
||
expect(config.getDatabaseUri()).toEqual("jobly"); | ||
process.env.NODE_ENV = "test"; | ||
|
||
expect(config.getDatabaseUri()).toEqual("jobly_test"); | ||
}); | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
"use strict"; | ||
/** Database setup for jobly. */ | ||
const { Client } = require("pg"); | ||
const { getDatabaseUri } = require("./config"); | ||
|
||
let db; | ||
|
||
if (process.env.NODE_ENV === "production") { | ||
db = new Client({ | ||
connectionString: getDatabaseUri(), | ||
ssl: { | ||
rejectUnauthorized: false | ||
} | ||
}); | ||
} else { | ||
db = new Client({ | ||
connectionString: getDatabaseUri() | ||
}); | ||
} | ||
|
||
db.connect(); | ||
|
||
module.exports = db; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/** ExpressError extends normal JS error so we can | ||
* add a status when we make an instance of it. | ||
* | ||
* The error-handling middleware will return this. | ||
*/ | ||
|
||
class ExpressError extends Error { | ||
constructor(message, status) { | ||
super(); | ||
this.message = message; | ||
this.status = status; | ||
} | ||
} | ||
|
||
/** 404 NOT FOUND error. */ | ||
|
||
class NotFoundError extends ExpressError { | ||
constructor(message = "Not Found") { | ||
super(message, 404); | ||
} | ||
} | ||
|
||
/** 401 UNAUTHORIZED error. */ | ||
|
||
class UnauthorizedError extends ExpressError { | ||
constructor(message = "Unauthorized") { | ||
super(message, 401); | ||
} | ||
} | ||
|
||
/** 400 BAD REQUEST error. */ | ||
|
||
class BadRequestError extends ExpressError { | ||
constructor(message = "Bad Request") { | ||
super(message, 400); | ||
} | ||
} | ||
|
||
/** 403 BAD REQUEST error. */ | ||
|
||
class ForbiddenError extends ExpressError { | ||
constructor(message = "Bad Request") { | ||
super(message, 403); | ||
} | ||
} | ||
|
||
module.exports = { | ||
ExpressError, | ||
NotFoundError, | ||
UnauthorizedError, | ||
BadRequestError, | ||
ForbiddenError, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
const { BadRequestError } = require("../expressError"); | ||
|
||
// THIS NEEDS SOME GREAT DOCUMENTATION. | ||
|
||
function sqlForPartialUpdate(dataToUpdate, jsToSql) { | ||
const keys = Object.keys(dataToUpdate); | ||
if (keys.length === 0) throw new BadRequestError("No data"); | ||
|
||
// {firstName: 'Aliya', age: 32} => ['"first_name"=$1', '"age"=$2'] | ||
const cols = keys.map((colName, idx) => | ||
`"${jsToSql[colName] || colName}"=$${idx + 1}`, | ||
); | ||
|
||
return { | ||
setCols: cols.join(", "), | ||
values: Object.values(dataToUpdate), | ||
}; | ||
} | ||
|
||
module.exports = { sqlForPartialUpdate }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
const jwt = require("jsonwebtoken"); | ||
const { SECRET_KEY } = require("../config"); | ||
|
||
/** return signed JWT from user data. */ | ||
|
||
function createToken(user) { | ||
console.assert(user.isAdmin !== undefined, | ||
"createToken passed user without isAdmin property"); | ||
|
||
let payload = { | ||
username: user.username, | ||
isAdmin: user.isAdmin || false, | ||
}; | ||
|
||
return jwt.sign(payload, SECRET_KEY); | ||
} | ||
|
||
module.exports = { createToken }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
const jwt = require("jsonwebtoken"); | ||
const { createToken } = require("./tokens"); | ||
const { SECRET_KEY } = require("../config"); | ||
|
||
describe("createToken", function () { | ||
test("works: not admin", function () { | ||
const token = createToken({ username: "test", is_admin: false }); | ||
const payload = jwt.verify(token, SECRET_KEY); | ||
expect(payload).toEqual({ | ||
iat: expect.any(Number), | ||
username: "test", | ||
isAdmin: false, | ||
}); | ||
}); | ||
|
||
test("works: admin", function () { | ||
const token = createToken({ username: "test", isAdmin: true }); | ||
const payload = jwt.verify(token, SECRET_KEY); | ||
expect(payload).toEqual({ | ||
iat: expect.any(Number), | ||
username: "test", | ||
isAdmin: true, | ||
}); | ||
}); | ||
|
||
test("works: default no admin", function () { | ||
// given the security risk if this didn't work, checking this specifically | ||
const token = createToken({ username: "test" }); | ||
const payload = jwt.verify(token, SECRET_KEY); | ||
expect(payload).toEqual({ | ||
iat: expect.any(Number), | ||
username: "test", | ||
isAdmin: false, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
CREATE TABLE companies ( | ||
handle VARCHAR(25) PRIMARY KEY CHECK (handle = lower(handle)), | ||
name TEXT UNIQUE NOT NULL, | ||
num_employees INTEGER CHECK (num_employees >= 0), | ||
description TEXT NOT NULL, | ||
logo_url TEXT | ||
); | ||
|
||
CREATE TABLE users ( | ||
username VARCHAR(25) PRIMARY KEY, | ||
password TEXT NOT NULL, | ||
first_name TEXT NOT NULL, | ||
last_name TEXT NOT NULL, | ||
email TEXT NOT NULL | ||
CHECK (position('@' IN email) > 1), | ||
is_admin BOOLEAN NOT NULL DEFAULT FALSE | ||
); | ||
|
||
CREATE TABLE jobs ( | ||
id SERIAL PRIMARY KEY, | ||
title TEXT NOT NULL, | ||
salary INTEGER CHECK (salary >= 0), | ||
equity NUMERIC CHECK (equity <= 1.0), | ||
company_handle VARCHAR(25) NOT NULL | ||
REFERENCES companies ON DELETE CASCADE | ||
); | ||
|
||
CREATE TABLE applications ( | ||
username VARCHAR(25) | ||
REFERENCES users ON DELETE CASCADE, | ||
job_id INTEGER | ||
REFERENCES jobs ON DELETE CASCADE, | ||
PRIMARY KEY (username, job_id) | ||
); |
Oops, something went wrong.