This commit is contained in:
QkoSad
2023-08-08 16:02:54 +03:00
commit 0a7a469d56
315 changed files with 426907 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
PORT=3003
MONGODB_URI='mongodb+srv://admin:admin@cluster1.ciuxwxd.mongodb.net/blogApp?retryWrites=true&w=majority'
TEST_MONGODB_URI='mongodb+srv://admin:admin@cluster1.ciuxwxd.mongodb.net/testBlogApp?retryWrites=true&w=majority'
SECRET='kdsajf90u234ijkasl;sdafds90812jpsakdy3894ioeklj321;ljx098zxxc'
+1
View File
@@ -0,0 +1 @@
missing testing execise 4.23 maybe even 4.8 -4.14
+22
View File
@@ -0,0 +1,22 @@
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const blogsRouter = require("./controllers/blogs");
const usersRouter = require("./controllers/users");
const loginRouter = require("./controllers/login");
const config = require("./utils/config");
const middleware = require("./utils/middleware");
const app = express();
mongoose.connect(config.MONGODB_URI).then(() => {
console.log("connected to mongodb");
});
app.use(cors());
app.use(express.json());
app.use(middleware.tokenExtractor);
app.use("/api/blogs" , blogsRouter);
app.use("/api/users", usersRouter);
app.use("/api/login", loginRouter);
module.exports = app;
+56
View File
@@ -0,0 +1,56 @@
const blogsRouter = require("express").Router();
const Blog = require("../models/blog");
const User = require("../models/user");
const middleware = require("../utils/middleware");
blogsRouter.get("", (request, response) => {
Blog.find({})
.populate("user", { name: 1 })
.then((blogs) => {
response.json(blogs);
});
});
blogsRouter.delete("/:id", middleware.userExtractor, async (req, res) => {
const id = req.params.id;
const blog = await Blog.findById(id);
let result = null;
const userId = req.user._id.toString();
if (blog.user.toString() === userId) {
const newUser = {
...req.user._doc,
blogs: [...req.user._doc.blogs.filter((el) => el.toString() !== id)],
};
await User.findOneAndUpdate({ _id: userId }, newUser);
result = await Blog.findByIdAndDelete(id);
return res.json(result);
}
return res.end();
});
blogsRouter.put("/:id", (req, res) => {
const id = req.params.id;
Blog.findOneAndUpdate({ _id: id }, req.body).then((result) => {
res.json(result);
});
});
blogsRouter.post("", middleware.userExtractor, async (req, res) => {
const { title, url } = req.body;
const user = req.user;
const blog = new Blog({
title,
author: user.name,
url,
likes: 0,
user: user.id,
});
const savedBlog = await blog.save();
user.blogs = user.blogs.concat(savedBlog._id);
user.save();
res.json(savedBlog);
});
module.exports = blogsRouter;
+24
View File
@@ -0,0 +1,24 @@
const loginRouter = require("express").Router();
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const User = require("../models/user");
const config = require("../utils/config");
loginRouter.post("", async (req, res) => {
const { username, password } = req.body;
const user = await User.findOne({ username });
const passwordCorrect =
user === null ? false : await bcrypt.compare(password, user.password);
if (!(user && passwordCorrect))
return res.status(401).json({ error: "invalid username or passowrd" });
const userForToken = {
username: user.username,
id: user._id,
};
const token = jwt.sign(userForToken, config.SECRET);
res.status(200).send({ token, username: user.username, name: user.name });
});
module.exports = loginRouter;
+36
View File
@@ -0,0 +1,36 @@
const usersRouter = require("express").Router();
const User = require("../models/user");
const bcrypt = require("bcrypt");
usersRouter.get("", (request, response) => {
User.find({}).then((users) => {
response.json(users);
});
});
/*
usersRouter.delete("/:id", (request, response) => {
const id = request.params.id;
User.findByIdAndDelete(id).then((users) => response.json(users));
});
usersRouter.put("/:id", (request, response) => {
const id = request.params.id;
const data = { ...request.body };
User.findOneAndUpdate({ _id: id }, data).then((result) => {
response.json(result);
});
});
*/
usersRouter.post("", async (request, response) => {
const { username, password, name } = request.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user = new User({ username, password: hashedPassword, name });
try {
const savedUser = await user.save();
response.status(201).json(savedUser);
} catch (err) {
response.status(400).send(err._message);
}
});
module.exports = usersRouter;
+25
View File
@@ -0,0 +1,25 @@
const mongoose = require("mongoose");
const blogSchema = new mongoose.Schema({
title: String,
author: String,
url: String,
likes: Number,
comments: [String],
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
});
blogSchema.set("toJSON", {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString();
delete returnedObject._id;
delete returnedObject.__v;
},
});
const Blog = mongoose.model("Blog", blogSchema);
module.exports = Blog;
+26
View File
@@ -0,0 +1,26 @@
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
username: { type: String, minlength: 3, require: true },
password: { type: String, require: true },
name: String,
blogs: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Blog",
},
],
});
userSchema.set("toJSON", {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString();
delete returnedObject._id;
delete returnedObject.__v;
delete returnedObject.password;
},
});
const User = mongoose.model("User", userSchema);
module.exports = User;
+9280
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
{
"name": "bloglistpt4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "NODE_ENV=developmnet nodemon server.js",
"test": "NODE_ENV=test jest --verbose"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.1.0",
"cors": "^2.8.5",
"dotenv": "^16.1.4",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.0",
"mongoose": "^7.2.3"
},
"devDependencies": {
"jest": "^29.5.0",
"nodemon": "^2.0.22",
"supertest": "^6.3.3"
},
"jest": {
"testEnvironment": "node"
}
}
+6
View File
@@ -0,0 +1,6 @@
const config = require('./utils/config')
const logger = require('./utils/logger')
const app = require('./app')
app.listen(config.PORT, () => {
logger.info(`Server running on port ${config.PORT}`)
})
+7
View File
@@ -0,0 +1,7 @@
const mongoose = require('mongoose')
console.log(mongoose.Schema)
console.log(mongoose.SchemaType)
+11
View File
@@ -0,0 +1,11 @@
curl http://localhost:3003/api/blogs | json_pp -json_opt pretty,canonical
curl http://localhost:3003/api/users | json_pp -json_opt pretty,canonical
curl -H "Content-Type: application/json" -X POST -d '{"title":"title1"}' http://localhost:3003/api/blogs | json_pp -json_opt pretty,canonical
curl -H "Content-Type: application/json" -X POST -d '{"username":"tomy1213","password":"tommy123","name":"Tonny Montana"}' http://localhost:3003/api/users | json_pp -json_opt pretty,canonical
curl -H "Content-Type: application/json" -X POST -d '{"username":"tommy","password":"tommy123"}' http://localhost:3003/api/login | json_pp -json_opt pretty,canonical
curl -H "Content-Type: application/json" -H "Authorization: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRvbW15IiwiaWQiOiI2NDg5NGQwOGVjOGQ0ZTgxMGRlZDQzZDEiLCJpYXQiOjE2ODY3MTk4MDl9.Vb0E6JNbWZTSiHXtXUnt7pT_yLMy8novvFAOqxoYKFA" -X POST -d '{"title":"title1"}' http://localhost:3003/api/blogs | json_pp -json_opt pretty,canonical
+8
View File
@@ -0,0 +1,8 @@
const listHelper = require("../utils/list_helper");
test("dummy returns one", () => {
const blogs = [];
const result = listHelper.dummy(blogs);
expect(result).toBe(1);
});
+58
View File
@@ -0,0 +1,58 @@
const listHelper = require("../utils/list_helper");
describe("total likes", () => {
const blogs = [
{
_id: "5a422a851b54a676234d17f7",
title: "React patterns",
author: "Michael Chan",
url: "https://reactpatterns.com/",
likes: 7,
__v: 0,
},
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html",
likes: 5,
__v: 0,
},
{
_id: "5a422b3a1b54a676234d17f9",
title: "Canonical string reduction",
author: "Edsger W. Dijkstra",
url: "http://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD808.html",
likes: 12,
__v: 0,
},
{
_id: "5a422b891b54a676234d17fa",
title: "First class tests",
author: "Robert C. Martin",
url: "http://blog.cleancoder.com/uncle-bob/2017/05/05/TestDefinitions.htmll",
likes: 10,
__v: 0,
},
{
_id: "5a422ba71b54a676234d17fb",
title: "TDD harms architecture",
author: "Robert C. Martin",
url: "http://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html",
likes: 0,
__v: 0,
},
{
_id: "5a422bc61b54a676234d17fc",
title: "Type wars",
author: "Robert C. Martin",
url: "http://blog.cleancoder.com/uncle-bob/2016/05/01/TypeWars.html",
likes: 2,
__v: 0,
},
];
test('testing likes',()=>{
const result= listHelper.totalLikes(blogs)
expect(result).toBe(36)
})
});
+66
View File
@@ -0,0 +1,66 @@
const listHelper = require("../utils/list_helper");
describe("maxLikes", () => {
const blogs = [
{
_id: "5a422a851b54a676234d17f7",
title: "React patterns",
author: "Michael Chan",
url: "https://reactpatterns.com/",
likes: 7,
__v: 0,
},
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html",
likes: 5,
__v: 0,
},
{
_id: "5a422b3a1b54a676234d17f9",
title: "Canonical string reduction",
author: "Edsger W. Dijkstra",
url: "http://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD808.html",
likes: 12,
__v: 0,
},
{
_id: "5a422b891b54a676234d17fa",
title: "First class tests",
author: "Robert C. Martin",
url: "http://blog.cleancoder.com/uncle-bob/2017/05/05/TestDefinitions.htmll",
likes: 10,
__v: 0,
},
{
_id: "5a422ba71b54a676234d17fb",
title: "TDD harms architecture",
author: "Robert C. Martin",
url: "http://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html",
likes: 0,
__v: 0,
},
{
_id: "5a422bc61b54a676234d17fc",
title: "Type wars",
author: "Robert C. Martin",
url: "http://blog.cleancoder.com/uncle-bob/2016/05/01/TypeWars.html",
likes: 2,
__v: 0,
},
];
test("most Liked Blog", () => {
const result = listHelper.favoriteBlog(blogs);
expect(result).toBe(7);
});
test("most Blogs", () => {
const result = listHelper.mostBlogs(blogs);
expect(result).toBe(3);
});
test("most Liked author", () => {
const result = listHelper.mostLikes(blogs);
expect(result).toBe(17);
});
});
+20
View File
@@ -0,0 +1,20 @@
const mongoose = require('mongoose')
const supertest = require('supertest')
const app = require('../app')
const api = supertest(app)
test('blogs are returned as json', async () => {
await api
.get('/api/blogs')
.expect(200)
.expect('Content-Type', /application\/json/)
})
test('blog is being posted',async()=>{
await api.post('/api/blogs').send({title:'title2'})
const response = await api.get('api/blogs')
})
afterAll(async () => {
await mongoose.connection.close()
})
+12
View File
@@ -0,0 +1,12 @@
require("dotenv").config();
const MONGODB_URI =
process.env.NODE_ENV === "test"
? process.env.TEST_MONGODB_URI
: process.env.MONGODB_URI;
module.exports = {
SECRET:process.env.SECRET,
MONGODB_URI,
PORT: process.env.PORT,
};
+30
View File
@@ -0,0 +1,30 @@
const dummy = (blogs) => {
return 1;
};
const totalLikes = (blogs) => {
return blogs.reduce((acc, cur) => acc + cur.likes, 0);
};
const favoriteBlog = (blogs) => {
let result = blogs.sort((a, b) => a.score - b.score);
return result[0].likes;
};
const mostLikes = (blogs) => {
let authors = new Map();
blogs.forEach((el) => {
if (authors.has(el.author))
authors.set(el.author, authors.get(el.author) + el.likes);
else authors.set(el.author, el.likes);
});
return Math.max(...authors.values())
};
const mostBlogs = (blogs) => {
let authors = new Map();
blogs.forEach((el) => {
if (authors.has(el.author))
authors.set(el.author, authors.get(el.author) + 1);
else authors.set(el.author, 1);
});
return Math.max(...authors.values())
};
module.exports = { dummy, mostLikes, mostBlogs, totalLikes, favoriteBlog };
+12
View File
@@ -0,0 +1,12 @@
const info = (...params) => {
console.log(...params);
};
const error = (...params) => {
console.error(...params);
};
module.exports = {
info,
error,
};
+22
View File
@@ -0,0 +1,22 @@
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const config = require("./config");
const tokenExtractor = (req, res, next) => {
const authorization = req.get("authorization");
if (authorization && authorization.startsWith("Bearer "))
req.token = authorization.replace("Bearer ", "");
next();
};
const userExtractor = async (req, res, next) => {
const decodedToken = jwt.verify(req.token, config.SECRET);
if (!decodedToken.id) return res.status(401).json({ error: "invalid token" });
const user = await User.findById(decodedToken.id);
console.log('user from the middleware',user)
req.user = user;
next();
};
module.exports = { tokenExtractor, userExtractor };