Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Daniel t impliment crud for rating #57

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
415 changes: 347 additions & 68 deletions starter-project-backend-g32/package-lock.json

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions starter-project-backend-g32/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ import express, {Application, Request, Response, NextFunction, json} from 'expre
import dotenv from 'dotenv';

dotenv.config();
import routes from "./routes";
// import routes from "./routes";
import articleRoutes from './routes/article'
const ratingRouter = require("./routes/rating.routes");



const app: Application = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use("/" , json({}));
app.use("/api/v1", require('../src/routes/routes'));
app.use("/users/:userID/posts/:postID/rates", routes.rateRouter);
// app.use("/api/v1", require('../src/routes/routes'));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove unused routes

app.use('/api/v1/articles', articleRoutes)
app.use('/api/v1/rating', ratingRouter)


export default app;

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const Rating = require("../models/rating");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the file should be a typescript file. plus you can simply import the module without setting up exporting file.

const { crudControllers } = require("../utils/ratingCRUD");

module.exports = crudControllers(Rating);
24 changes: 24 additions & 0 deletions starter-project-backend-g32/src/models/rating.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const mongoose = require("mongoose");

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add interface definition for the model that extends from mongoose.Doucment, to state the definition of the schema, state the schema definitions and model definition based on this interface

const ratingSchema = mongoose.Schema({
stars: {
type: Number,
required: true,
min: [1, "rating too low"],
max: [5, "rating too high"],
},
article: {
type: mongoose.Types.ObjectId,
ref: "Article",
required: true
},
user: {
type: mongoose.Types.ObjectId,
ref: "User",
required: true
},
});

const Rating = mongoose.model("Rating", ratingSchema);

module.exports = Rating;
13 changes: 13 additions & 0 deletions starter-project-backend-g32/src/routes/rating.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const express = require('express')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use import statements to adhere to es6 importing module pattern

const router = express.Router()
const ratingController = require('../controllers/rating.controller')


router.route('/').get(ratingController.getMany)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use articles route to handle rating, since they are dependent.

router.route('/').post(ratingController.createOne)

router.route('/:id').get(ratingController.getOne)
router.route('/:id').put(ratingController.updateOne)
router.route('/:id').delete(ratingController.removeOne)

module.exports = router
2 changes: 1 addition & 1 deletion starter-project-backend-g32/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import app from "./app"
import mongoose from 'mongoose';

const PORT = process.env.PORT || 8000
const DB_URI = process.env.MONGO_URI || "mongodb://localhost:27017/usersdb";
const DB_URI = process.env.MONGO_URI || "mongodb://localhost:27017/blog";
mongoose.connect(DB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
Expand Down
72 changes: 72 additions & 0 deletions starter-project-backend-g32/src/tests/__tests__/rating.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import supertest from 'supertest';
import {MongoMemoryServer} from "mongodb-memory-server";
import app from "../../app"
const mongoose = require('mongoose');

// payloads For all the tests
const ratingPayload = {
"stars" : 5,
"article": "62d510eaf474e57abb69067e",
"user": "62d502a8fea5ce18b53f1240"
}

const wrongRatingPayload = {
"stars" : 5,
"article": "62d510eaf474e57abb69067e",
}

describe.only('Rating', ()=> {
beforeAll(async () => {
const mongoServer = await MongoMemoryServer.create();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use setup.db to open and close in memory server


await mongoose.connect(mongoServer.getUri());
});

afterAll(async () => {
await mongoose.disconnect();
await mongoose.connection.close();
});
describe('get Rating routes', ()=>{
describe('given the rating does not exist', () => {
it('should return a 404.', async () => {
const ratingId = new mongoose.Types.ObjectId('62d9bb72804a5a74621f838a');
await supertest(app).get(`/api/v1/rating/${ratingId}`).expect(404);
});
});

describe('given the rating does exist', () => {
it('should return a 200 and the rating info.', async () => {
//First lets create a rating
const {statusCode, body } = await supertest(app).post(`/api/v1/rating`).send(ratingPayload);
expect(statusCode).toBe(201);

const ratingId = body.data._id;
await supertest(app).get(`/api/v1/rating/${ratingId}`).expect(200);
});
});
});

describe('create Rating routes', ()=>{
describe('given the rating body is passed correctly', () => {
it('should return a 200 and create the rating.', async () => {
const {statusCode, body } = await supertest(app).post(`/api/v1/rating`).send(ratingPayload);
expect(statusCode).toBe(201);
const data = body.data;

expect(Object.keys(data).length).toEqual(5);
// expect(data).toEqual(expect.objectContaining({
// __v: expect.any(Number),
// _id: expect.any(String),
// article: expect.any(String),
// starts: expect.any(Number),
// user: expect.any(String)
// }))
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add more testing to the files, simulate what happens when a user rates again, test update rating and other files too.

});
describe('given the rating request body is passed incorrectly', () => {
it('should return a 400.', async () => {
await supertest(app).post(`/api/v1/rating`).send(wrongRatingPayload).expect(400);
});
});
});
});
86 changes: 86 additions & 0 deletions starter-project-backend-g32/src/utils/ratingCRUD.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const getOne = (model) => async (req, res) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file should be ts file, plus we don't need other folders, such as utils we can use controllers folder to handle business logics, clone master branch and work on that. plus we don't need crud for rating since its dependent on article you can add your function their.

try {
const doc = await model.findOne({ _id: req.params.id }).lean().exec();

if (!doc) {
return res.status(404).end();
}

res.status(200).json({ data: doc });
} catch (e) {
console.error(e);
res.status(400).end();
}
};

const getMany = (model) => async (req, res) => {
try {
const docs = await model.find().lean().exec();

res.status(200).json({ data: docs });
} catch (e) {
console.error(e);
res.status(400).end();
}
};

const createOne = (model) => async (req, res) => {
try {
const doc = await model.create({ ...req.body });
res.status(201).json({ data: doc });
} catch (e) {
console.error(e);
res.status(400).end();
}
};

const updateOne = (model) => async (req, res) => {
try {
const updatedDoc = await model
.findOneAndUpdate(
{
_id: req.params.id,
},
req.body,
{ new: true }
)
.lean()
.exec();

if (!updatedDoc) {
return res.status(404).end();
}

res.status(200).json({ data: updatedDoc });
} catch (e) {
console.error(e);
res.status(400).end();
}
};

const removeOne = (model) => async (req, res) => {
try {
const removed = await model.findOneAndRemove({
_id: req.params.id,
});

if (!removed) {
return res.status(404).end();
}

return res.status(200).json({ data: removed });
} catch (e) {
console.error(e);
res.status(400).end();
}
};

const crudControllers = (model) => ({
removeOne: removeOne(model),
updateOne: updateOne(model),
getMany: getMany(model),
getOne: getOne(model),
createOne: createOne(model),
});

module.exports = { crudControllers };