translate tutorial to node/sql framework

This commit is contained in:
andrzej 2024-05-27 16:12:11 +02:00
parent c749adff34
commit 5a406be06e
6 changed files with 414 additions and 369 deletions

View File

@ -1,52 +0,0 @@
import jwt from "jsonwebtoken";
import passport from "passport";
import jwtSecret from "../config/jwtConfig";
import { db } from "../db.mjs";
import logger from "../logger.mjs";
module.exports = (app) => {
app.post("/loginUser", (req, res, next) => {
passport.authenticate("login", (err, users, info) => {
if (err) {
logger.error(`error ${err}`);
}
if (info !== undefined) {
logger.error(info.message);
if (info.message === "bad username") {
res.status(401).send(info.message);
} else {
res.status(403).send(info.message);
}
} else {
req.logIn(users, async () => {
let user = await db("users")
.select("*")
.where({ username: req.body.username });
user = user[0];
const token = jwt.sign({ id: user.id }, jwtSecret.secret, {
expiresIn: 60 * 60,
});
res.status(200).send({
auth: true,
token,
message: "user found & logged in",
});
// User.findOne({
// where: {
// username: req.body.username,
// },
// }).then((user) => {
// const token = jwt.sign({ id: user.id }, jwtSecret.secret, {
// expiresIn: 60 * 60,
// });
// res.status(200).send({
// auth: true,
// token,
// message: "user found & logged in",
// });
// });
});
}
})(req, res, next);
});
};

77
auth/auth.mjs Normal file
View File

@ -0,0 +1,77 @@
import passport from "passport";
import * as passportLocal from "passport-local";
import { db } from "../db.mjs";
import logger from "../logger.mjs";
import bcrypt from "bcrypt";
//This code saves the information provided by the user to the database, and then sends the user information to the next middleware if successful.
passport.use(
"signup",
new localStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await db("users").insert({ email, password });
return done(null, user);
} catch (error) {
done(error);
}
},
),
);
async function isValidPwd(user, pwd) {
return bcrypt.compare(pwd, user.password);
}
passport.use(
"login",
new localStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await db("users").select("*").where({ email });
if (user.length === 0) {
return done(null, false, { message: "User not found" });
}
user = user[0];
const validate = await isValidPwd(user, password);
if (!validate) {
return done(null, false, { message: "Wrong Password" });
}
return done(null, user, { message: "Logged in Successfully" });
} catch (error) {
return done(error);
}
},
),
);
// ...
const JWTstrategy = require("passport-jwt").Strategy;
const ExtractJWT = require("passport-jwt").ExtractJwt;
//This code uses passport-jwt to extract the JWT from the query parameter. It then verifies that this token has been signed with the secret or key set during logging in (TOP_SECRET). If the token is valid, the user details are passed to the next middleware.
passport.use(
new JWTstrategy(
{
secretOrKey: "TOP_SECRET",
jwtFromRequest: ExtractJWT.fromUrlQueryParameter("secret_token"),
},
async (token, done) => {
try {
return done(null, token.user);
} catch (error) {
done(error);
}
},
),
);

View File

@ -39,26 +39,60 @@ export const getEndpoints = (dbObject) => {
return router; return router;
}; };
export const postEndpoints = (db, data) => { export const protectedEndpoints = (db, data) => {
const router = express.Router(); const router = express.Router();
protectedEndpoint(router, Story, "create", "insert", db, data); writeEndpoint(router, Story, "create", "insert", db, data);
protectedEndpoint(router, Story, "edit", "update", db, data); writeEndpoint(router, Story, "edit", "update", db, data);
protectedEndpoint(router, Story, "delete", "update", db, data); writeEndpoint(router, Story, "delete", "update", db, data);
protectedEndpoint(router, Submission, "create", "insert", db, data); writeEndpoint(router, Submission, "create", "insert", db, data);
protectedEndpoint(router, Submission, "edit", "update", db, data); writeEndpoint(router, Submission, "edit", "update", db, data);
protectedEndpoint(router, Submission, "delete", "update", db, data); writeEndpoint(router, Submission, "delete", "update", db, data);
protectedEndpoint(router, Publication, "create", "insert", db, data); writeEndpoint(router, Publication, "create", "insert", db, data);
protectedEndpoint(router, Publication, "edit", "update", db, data); writeEndpoint(router, Publication, "edit", "update", db, data);
protectedEndpoint(router, Publication, "delete", "del", db, data); writeEndpoint(router, Publication, "delete", "del", db, data);
//Auth endpoints
router.post(
"/signup",
passport.authenticate("signup", { session: false }),
async (req, res) => {
res.json({
message: "Signup successful",
user: req.user,
});
},
);
router.post("/login", async (req, res, next) => {
passport.authenticate("login", async (err, user, info) => {
try {
if (err || !user) {
const error = new Error("An error occurred.");
return next(error);
}
req.login(user, { session: false }, async (error) => {
if (error) return next(error);
const body = { _id: user._id, email: user.email };
const token = require("jsonwebtoken").sign(
{ user: body },
"TOP_SECRET",
);
return res.json({ token });
});
} catch (error) {
return next(error);
}
})(req, res, next);
});
return router; return router;
}; };
const protectedEndpoint = (router, Entity, path, method, db, data) => { const writeEndpoint = (router, Entity, path, method, db, data) => {
router.post( router.post(
`/${Entity.name.toLowerCase()}/${path}`, `/${Entity.name.toLowerCase()}/${path}`,
passport.authenticate("jwt", { session: false }, (_, res) => { passport.authenticate("jwt", { session: false }),
res.json({ message: "protected endpoint" });
}),
async (req, res) => { async (req, res) => {
try { try {
logger.trace({ data: req.body }, "POST request received"); logger.trace({ data: req.body }, "POST request received");

19
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"chai": "^4.3.8", "chai": "^4.3.8",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
@ -595,6 +596,24 @@
} }
] ]
}, },
"node_modules/bcrypt": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
"integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==",
"hasInstallScript": true,
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.11",
"node-addon-api": "^5.0.0"
},
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/bcrypt/node_modules/node-addon-api": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
},
"node_modules/binary-extensions": { "node_modules/binary-extensions": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",

View File

@ -9,6 +9,7 @@
"author": "Andrzej Stepien", "author": "Andrzej Stepien",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {
"bcrypt": "^5.1.1",
"body-parser": "^1.20.2", "body-parser": "^1.20.2",
"chai": "^4.3.8", "chai": "^4.3.8",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",

View File

@ -1,311 +1,277 @@
import {describe} from "mocha"; import { describe } from "mocha";
import chai, { expect } from "chai"; import chai, { expect } from "chai";
import bodyParser from "body-parser"; import bodyParser from "body-parser";
import express from 'express' import express from "express";
import chaiHttp from "chai-http"; import chaiHttp from "chai-http";
import { testDb as db } from "../db.mjs"; import { testDb as db } from "../db.mjs";
import { Data } from "../objects/Data.mjs"; import { Data } from "../objects/Data.mjs";
import { beforeEach, afterEach } from "mocha"; import { beforeEach, afterEach } from "mocha";
import { postEndpoints, getEndpoints } from "../objects/Endpoints.mjs"; import { protectedEndpoints, getEndpoints } from "../objects/Endpoints.mjs";
chai.use(chaiHttp) chai.use(chaiHttp);
const app = express() const app = express();
const data = new Data(db) const data = new Data(db);
await data.init() await data.init();
app.use(bodyParser.json()) app.use(bodyParser.json());
app.use('/api',getEndpoints(data)) app.use("/api", getEndpoints(data));
app.use('/api', postEndpoints(db,data)) app.use("/api", protectedEndpoints(db, data));
describe("testing endpoints...", async function () {
describe("testing endpoints...",async function(){ describe("Testing GET endpoints", async function () {
describe("Testing GET endpoints", async function(){ describe("GET stories", async function () {
describe("GET stories",async function(){ it("should return a status code of 200 and an array", async function () {
it("should return a status code of 200 and an array", async function(){ const res = await chai.request(app).get("/api/stories");
const res = await chai.request(app).get('/api/stories') expect(res).to.have.status(200);
expect(res).to.have.status(200) expect(res.body).to.be.a("array");
expect(res.body).to.be.a('array') });
}) });
}) describe("GET submissions", async function () {
describe("GET submissions",async function(){ it("should return a status code of 200 and an array", async function () {
it("should return a status code of 200 and an array", async function(){ const res = await chai.request(app).get("/api/submissions");
const res = await chai.request(app).get('/api/submissions') expect(res).to.have.status(200);
expect(res).to.have.status(200) expect(res.body).to.be.a("array");
expect(res.body).to.be.a('array') });
}) });
}) describe("GET publications", async function () {
describe("GET publications",async function(){ it("should return a status code of 200 and an array", async function () {
it("should return a status code of 200 and an array", async function(){ const res = await chai.request(app).get("/api/publications");
const res = await chai.request(app).get('/api/publications') expect(res).to.have.status(200);
expect(res).to.have.status(200) expect(res.body).to.be.a("array");
expect(res.body).to.be.a('array') });
}) });
}) });
}) describe("testing /create endpoints", async function () {
describe("testing /create endpoints", async function(){ describe("/story/create", async function () {
describe("/story/create",async function(){
const goodData = { const goodData = {
title:"#test", title: "#test",
word_count:111, word_count: 111,
deleted:0 deleted: 0,
} };
const badData = { const badData = {
title:1, title: 1,
word_count:"not a number" word_count: "not a number",
} };
afterEach(async function(){ afterEach(async function () {
await db('stories') await db("stories").where("title", goodData.title).del();
.where('title',goodData.title) });
.del() it("should return 200 if a valid request is made", async function () {
}) const res = await chai
it("should return 200 if a valid request is made",async function(){ .request(app)
const res = await chai.request(app) .post("/api/story/create")
.post('/api/story/create') .send(goodData);
.send(goodData) expect(res).to.have.status(200);
expect(res).to.have.status(200) });
}) it("should return 400 if an invalid request is made", async function () {
it("should return 400 if an invalid request is made",async function(){ const res = await chai
const res = await chai.request(app) .request(app)
.post('/api/story/create') .post("/api/story/create")
.send(badData) .send(badData);
expect(res).to.have.status(400) expect(res).to.have.status(400);
}) });
it("the new entry should exist in the database",async function(){ it("the new entry should exist in the database", async function () {
await chai.request(app) await chai.request(app).post("/api/story/create").send(goodData);
.post('/api/story/create') const res = await db("stories")
.send(goodData) .select("*")
const res = await db('stories') .where("title", goodData.title);
.select('*') expect(res[0].title).to.eql(goodData.title);
.where('title',goodData.title) });
expect(res[0].title).to.eql(goodData.title) });
}) describe("/publication/create", async function () {
})
describe("/publication/create",async function(){
const goodData = { const goodData = {
title:"#test", title: "#test",
link:"www.internet.com", link: "www.internet.com",
deleted:0 deleted: 0,
} };
const badData = { const badData = {
title:1, title: 1,
link:1 link: 1,
} };
afterEach(async function(){ afterEach(async function () {
await db('pubs') await db("pubs").where("title", goodData.title).del();
.where('title',goodData.title) });
.del() it("should return 200 if a valid request is made", async function () {
}) const res = await chai
it("should return 200 if a valid request is made",async function(){ .request(app)
const res = await chai.request(app) .post("/api/publication/create")
.post('/api/publication/create') .send(goodData);
.send(goodData) expect(res).to.have.status(200);
expect(res).to.have.status(200) });
}) it("should return 400 if an invalid request is made", async function () {
it("should return 400 if an invalid request is made",async function(){ const res = await chai
const res = await chai.request(app) .request(app)
.post('/api/publication/create') .post("/api/publication/create")
.send(badData) .send(badData);
expect(res).to.have.status(400) expect(res).to.have.status(400);
}) });
it("the new entry should exist in the database",async function(){ it("the new entry should exist in the database", async function () {
await chai.request(app) await chai.request(app).post("/api/publication/create").send(goodData);
.post('/api/publication/create') const res = await db("pubs").select("*").where("title", goodData.title);
.send(goodData) expect(res[0].title).to.eql(goodData.title);
const res = await db('pubs') });
.select('*') });
.where('title',goodData.title) describe("/submission/create", async function () {
expect(res[0].title).to.eql(goodData.title)
})
})
describe("/submission/create",async function(){
const goodData = { const goodData = {
story_id:1, story_id: 1,
pub_id:1, pub_id: 1,
response_id:1, response_id: 1,
date_submitted:"1066-01-01", date_submitted: "1066-01-01",
date_responded:"1066-01-01" date_responded: "1066-01-01",
} };
const badData = { const badData = {
story_id:"string", story_id: "string",
pub_id:1, pub_id: 1,
response_id:1, response_id: 1,
date_submitted:"1066-01-01", date_submitted: "1066-01-01",
date_responded:"1066-01-01" date_responded: "1066-01-01",
} };
afterEach(async function(){ afterEach(async function () {
await db('subs') await db("subs").where("date_submitted", goodData.date_submitted).del();
.where('date_submitted',goodData.date_submitted) });
.del() it("should return 200 if a valid request is made", async function () {
}) const res = await chai
it("should return 200 if a valid request is made",async function(){ .request(app)
const res = await chai.request(app) .post("/api/submission/create")
.post('/api/submission/create') .send(goodData);
.send(goodData) expect(res).to.have.status(200);
expect(res).to.have.status(200) });
}) it("should return 400 if an invalid request is made", async function () {
it("should return 400 if an invalid request is made",async function(){ const res = await chai
const res = await chai.request(app) .request(app)
.post('/api/submission/create') .post("/api/submission/create")
.send(badData) .send(badData);
expect(res).to.have.status(400) expect(res).to.have.status(400);
}) });
it("the new entry should exist in the database",async function(){ it("the new entry should exist in the database", async function () {
await chai.request(app) await chai.request(app).post("/api/submission/create").send(goodData);
.post('/api/submission/create') const res = await db("subs")
.send(goodData) .select("*")
const res = await db('subs') .where("date_submitted", goodData.date_submitted);
.select('*') expect(res[0].date_responded).to.eql(goodData.date_responded);
.where('date_submitted',goodData.date_submitted) });
expect(res[0].date_responded).to.eql(goodData.date_responded) });
}) });
describe("testing /edit endpoints", async function () {
}) describe("/story/edit", async function () {
})
describe("testing /edit endpoints",async function(){
describe("/story/edit",async function(){
const goodData = { const goodData = {
id:1, id: 1,
title:"#test", title: "#test",
word_count:111, word_count: 111,
deleted:0 deleted: 0,
} };
const badData = { const badData = {
id:"string" id: "string",
} };
let prev = {} let prev = {};
beforeEach(async function(){ beforeEach(async function () {
prev = await db('stories') prev = await db("stories").select("*").where("id", 1);
.select('*') prev = prev[0];
.where('id',1) });
prev = prev[0] afterEach(async function () {
}) await db("stories").where("id", 1).update(prev);
afterEach(async function(){ });
await db('stories') it("should return 200 when sent valid data", async function () {
.where('id',1) const res = await chai
.update(prev) .request(app)
}) .post("/api/story/edit")
it("should return 200 when sent valid data",async function(){ .send(goodData);
const res = await chai.request(app) expect(res).to.have.status(200);
.post('/api/story/edit') });
.send(goodData) it("should return 400 when sent invalid data", async function () {
expect(res).to.have.status(200) const res = await chai
}) .request(app)
it("should return 400 when sent invalid data",async function(){ .post("/api/story/edit")
const res = await chai.request(app) .send(badData);
.post('/api/story/edit') expect(res).to.have.status(400);
.send(badData) });
expect(res).to.have.status(400) it("the edit should be reflected in the database", async function () {
}) await chai.request(app).post("/api/story/edit").send(goodData);
it("the edit should be reflected in the database",async function(){ const res = await db("stories").select("*").where("id", goodData.id);
await chai.request(app) expect(res[0]).to.eql(goodData);
.post('/api/story/edit') });
.send(goodData) });
const res = await db('stories'). describe("/publication/edit", async function () {
select('*')
.where('id',goodData.id)
expect(res[0]).to.eql(goodData)
})
})
describe("/publication/edit",async function(){
const goodData = { const goodData = {
id:1, id: 1,
title:"#test", title: "#test",
link:"link", link: "link",
query_after_days:90, query_after_days: 90,
deleted:0 deleted: 0,
} };
const badData = { const badData = {
id:"string" id: "string",
} };
let prev = {} let prev = {};
beforeEach(async function(){ beforeEach(async function () {
prev = await db('pubs') prev = await db("pubs").select("*").where("id", 1);
.select('*') prev = prev[0];
.where('id',1) });
prev = prev[0] afterEach(async function () {
}) await db("pubs").where("id", 1).update(prev);
afterEach(async function(){ });
await db('pubs') it("should return 200 when sent valid data", async function () {
.where('id',1) const res = await chai
.update(prev) .request(app)
}) .post("/api/publication/edit")
it("should return 200 when sent valid data",async function(){ .send(goodData);
const res = await chai.request(app) expect(res).to.have.status(200);
.post('/api/publication/edit') });
.send(goodData) it("should return 400 when sent invalid data", async function () {
expect(res).to.have.status(200) const res = await chai
}) .request(app)
it("should return 400 when sent invalid data",async function(){ .post("/api/publication/edit")
const res = await chai.request(app) .send(badData);
.post('/api/publication/edit') expect(res).to.have.status(400);
.send(badData) });
expect(res).to.have.status(400) it("the edit should be reflected in the database", async function () {
}) await chai.request(app).post("/api/publication/edit").send(goodData);
it("the edit should be reflected in the database",async function(){ const res = await db("pubs").select("*").where("id", goodData.id);
await chai.request(app) expect(res[0]).to.eql(goodData);
.post('/api/publication/edit') });
.send(goodData) });
const res = await db('pubs'). describe("/submission/edit", async function () {
select('*')
.where('id',goodData.id)
expect(res[0]).to.eql(goodData)
})
})
describe("/submission/edit",async function(){
const goodData = { const goodData = {
id:1, id: 1,
story_id:1, story_id: 1,
pub_id:1, pub_id: 1,
response_id:1, response_id: 1,
date_submitted:"1066-01-01", date_submitted: "1066-01-01",
date_responded:"1066-01-01" date_responded: "1066-01-01",
} };
const badData = { const badData = {
story_id:"string", story_id: "string",
pub_id:1, pub_id: 1,
response_id:1, response_id: 1,
date_submitted:"1066-01-01", date_submitted: "1066-01-01",
date_responded:"1066-01-01" date_responded: "1066-01-01",
} };
let prev = {} let prev = {};
beforeEach(async function(){ beforeEach(async function () {
prev = await db('subs') prev = await db("subs").select("*").where("id", 1);
.select('*') prev = prev[0];
.where('id',1) });
prev = prev[0] afterEach(async function () {
}) await db("subs").where("id", 1).update(prev);
afterEach(async function(){ });
await db('subs') it("should return 200 when sent valid data", async function () {
.where('id',1) const res = await chai
.update(prev) .request(app)
}) .post("/api/submission/edit")
it("should return 200 when sent valid data",async function(){ .send(goodData);
const res = await chai.request(app) expect(res).to.have.status(200);
.post('/api/submission/edit') });
.send(goodData) it("should return 400 when sent invalid data", async function () {
expect(res).to.have.status(200) const res = await chai
}) .request(app)
it("should return 400 when sent invalid data",async function(){ .post("/api/submission/edit")
const res = await chai.request(app) .send(badData);
.post('/api/submission/edit') expect(res).to.have.status(400);
.send(badData) });
expect(res).to.have.status(400) it("the edit should be reflected in the database", async function () {
}) await chai.request(app).post("/api/submission/edit").send(goodData);
it("the edit should be reflected in the database",async function(){ const res = await db("subs").select("*").where("id", goodData.id);
await chai.request(app) expect(res[0]).to.eql(goodData);
.post('/api/submission/edit') });
.send(goodData) });
const res = await db('subs'). });
select('*') });
.where('id',goodData.id)
expect(res[0]).to.eql(goodData)
})
})
})
})