Compare commits
No commits in common. "b839aeba78fb51b0e4a542fc5dd76cb4ec718db7" and "8bb31432c72ac468c5c660eee36c50f557ee6f43" have entirely different histories.
b839aeba78
...
8bb31432c7
13 changed files with 34 additions and 387 deletions
|
|
@ -5,7 +5,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node src/app.js",
|
"start": "node src/app.js",
|
||||||
"dev": "node --watch src/app.js",
|
"dev": "node --watch src/app.js",
|
||||||
"test": "node --test"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,37 @@
|
||||||
const express = require("express");
|
const express = require('express')
|
||||||
const { addRoutes } = require("./routes");
|
const mongoose = require('mongoose')
|
||||||
const app = express();
|
|
||||||
|
|
||||||
app.use(express.json());
|
const app = express()
|
||||||
|
|
||||||
addRoutes(app);
|
const blogSchema = mongoose.Schema({
|
||||||
|
title: String,
|
||||||
|
author: String,
|
||||||
|
url: String,
|
||||||
|
likes: Number,
|
||||||
|
})
|
||||||
|
|
||||||
const PORT = 3003;
|
const Blog = mongoose.model('Blog', blogSchema)
|
||||||
|
|
||||||
|
const mongoUrl = 'mongodb://localhost/bloglist'
|
||||||
|
mongoose.connect(mongoUrl)
|
||||||
|
|
||||||
|
app.use(express.json())
|
||||||
|
|
||||||
|
app.get('/api/blogs', (request, response) => {
|
||||||
|
Blog.find({}).then((blogs) => {
|
||||||
|
response.json(blogs)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/api/blogs', (request, response) => {
|
||||||
|
const blog = new Blog(request.body)
|
||||||
|
|
||||||
|
blog.save().then((result) => {
|
||||||
|
response.status(201).json(result)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const PORT = 3003
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`Server running on port ${PORT}`);
|
console.log(`Server running on port ${PORT}`)
|
||||||
});
|
})
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
const mongoose = require('mongoose')
|
|
||||||
|
|
||||||
const blogSchema = mongoose.Schema({
|
|
||||||
title: String,
|
|
||||||
author: String,
|
|
||||||
url: String,
|
|
||||||
likes: Number,
|
|
||||||
})
|
|
||||||
|
|
||||||
const Blog = mongoose.model('Blog', blogSchema)
|
|
||||||
|
|
||||||
const mongoUrl = 'mongodb://localhost/bloglist'
|
|
||||||
mongoose.connect(mongoUrl)
|
|
||||||
|
|
||||||
module.exports = {models: {Blog}}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
const { models } = require("./db");
|
|
||||||
const Blog = models.Blog;
|
|
||||||
|
|
||||||
BASE_API_PATH = "/api";
|
|
||||||
|
|
||||||
const addRoutes = (app) => {
|
|
||||||
app.get(`${BASE_API_PATH}/blogs`, (request, response) => {
|
|
||||||
Blog.find({}).then((blogs) => {
|
|
||||||
response.json(blogs);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post(`${BASE_API_PATH}/blogs`, (request, response) => {
|
|
||||||
const blog = new Blog(request.body);
|
|
||||||
|
|
||||||
blog.save().then((result) => {
|
|
||||||
response.status(201).json(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = { addRoutes };
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
const reverse = (string) => {
|
|
||||||
return string.split("").reverse().join("");
|
|
||||||
};
|
|
||||||
|
|
||||||
const average = (array) => {
|
|
||||||
const reducer = (sum, item) => {
|
|
||||||
return sum + item;
|
|
||||||
};
|
|
||||||
|
|
||||||
return array.length === 0 ? 0 : array.reduce(reducer, 0) / array.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
const listHelper = (posts) => {
|
|
||||||
console.log("lol");
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const totalLikes = (posts) => {
|
|
||||||
if (!posts) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const likeCount = posts
|
|
||||||
.map((post) => post.likes)
|
|
||||||
.reduce((cum, value) => cum + value, 0);
|
|
||||||
|
|
||||||
return likeCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
const favoritePost = (posts) => {
|
|
||||||
if (!posts || posts.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const highestLikes = posts.reduce(
|
|
||||||
(max, post) => (post.likes > max ? (max = post.likes) : max),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
const favoritePost = posts.find((post) => post.likes == highestLikes);
|
|
||||||
|
|
||||||
return favoritePost;
|
|
||||||
};
|
|
||||||
|
|
||||||
const mostPosts = (posts) => {
|
|
||||||
if (!posts || posts.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const countMap = posts.reduce((acc, post) => {
|
|
||||||
acc[post.author] = (acc[post.author] || 0) + 1;
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const [author, postsCount] = Object.entries(countMap).reduce(
|
|
||||||
(max, entry) => (entry[1] > max[1] ? entry : max),
|
|
||||||
['', 0]
|
|
||||||
);
|
|
||||||
|
|
||||||
return { author, posts: postsCount };
|
|
||||||
};
|
|
||||||
|
|
||||||
const mostLikes = (posts) => {
|
|
||||||
if (!posts || posts.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const likesMap = posts.reduce((acc, post) => {
|
|
||||||
acc[post.author] = (acc[post.author] || 0) + post.likes;
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const [author, likesCount] = Object.entries(likesMap).reduce(
|
|
||||||
(max, entry) => (entry[1] > max[1] ? entry : max),
|
|
||||||
['', 0]
|
|
||||||
);
|
|
||||||
|
|
||||||
return { author, likes: likesCount };
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
reverse,
|
|
||||||
average,
|
|
||||||
listHelper,
|
|
||||||
totalLikes,
|
|
||||||
favoritePost,
|
|
||||||
mostPosts,
|
|
||||||
mostLikes
|
|
||||||
};
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
const { test, describe } = require('node:test')
|
|
||||||
const assert = require('node:assert')
|
|
||||||
|
|
||||||
const average = require('../src/utils').average
|
|
||||||
|
|
||||||
describe('average', () => {
|
|
||||||
test('of one value is the value itself', () => {
|
|
||||||
assert.strictEqual(average([1]), 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('of many is calculated right', () => {
|
|
||||||
assert.strictEqual(average([1, 2, 3, 4, 5, 6]), 3.5)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('of empty array is zero', () => {
|
|
||||||
assert.strictEqual(average([]), 0)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
const { test, describe } = require("node:test");
|
|
||||||
const assert = require("node:assert");
|
|
||||||
const { favoritePost } = require("../src/utils");
|
|
||||||
|
|
||||||
describe("favoritePost ", () => {
|
|
||||||
const posts = [
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 5,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 2,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const emptyArray = [];
|
|
||||||
|
|
||||||
const gibberish = "asdaSd123asd";
|
|
||||||
|
|
||||||
test("finds top properly", () => {
|
|
||||||
assert.strictEqual(favoritePost(posts), posts[0]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("works fine with empty array", () => {
|
|
||||||
assert.strictEqual(favoritePost(emptyArray), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails with gibberish input", () => {
|
|
||||||
const failedCall = () => {
|
|
||||||
favoritePost(gibberish);
|
|
||||||
};
|
|
||||||
assert.throws(failedCall, Error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
const { test, describe } = require("node:test");
|
|
||||||
const assert = require("node:assert");
|
|
||||||
const { listHelper } = require("../src/utils");
|
|
||||||
|
|
||||||
test("dummy returns one", () => {
|
|
||||||
const blogs = [];
|
|
||||||
|
|
||||||
const result = listHelper(blogs);
|
|
||||||
assert.strictEqual(result, 1);
|
|
||||||
});
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
const { test, describe } = require("node:test");
|
|
||||||
const assert = require("node:assert");
|
|
||||||
const { mostLikes } = require("../src/utils");
|
|
||||||
|
|
||||||
describe("most likes ", () => {
|
|
||||||
const posts = [
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 5,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 2,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "123",
|
|
||||||
title: "Lololo",
|
|
||||||
author: "John Doe",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 1,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const emptyArray = [];
|
|
||||||
|
|
||||||
const gibberish = "asdaSd123asd";
|
|
||||||
|
|
||||||
test("finds top author properly", () => {
|
|
||||||
assert.deepStrictEqual(mostLikes(posts), {
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
likes: 7,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("works fine with empty array", () => {
|
|
||||||
assert.strictEqual(mostLikes(emptyArray), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails with gibberish input", () => {
|
|
||||||
const failedCall = () => {
|
|
||||||
mostLikes(gibberish);
|
|
||||||
};
|
|
||||||
assert.throws(failedCall, Error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
const { test, describe } = require("node:test");
|
|
||||||
const assert = require("node:assert");
|
|
||||||
const { mostPosts } = require("../src/utils");
|
|
||||||
|
|
||||||
describe("most posts ", () => {
|
|
||||||
const posts = [
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 5,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 2,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "123",
|
|
||||||
title: "Lololo",
|
|
||||||
author: "John Doe",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 1,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const emptyArray = [];
|
|
||||||
|
|
||||||
const gibberish = "asdaSd123asd";
|
|
||||||
|
|
||||||
test("finds top author properly", () => {
|
|
||||||
assert.deepStrictEqual(mostPosts(posts), {
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
posts: 2,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("works fine with empty array", () => {
|
|
||||||
assert.strictEqual(mostPosts(emptyArray), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails with gibberish input", () => {
|
|
||||||
const failedCall = () => {
|
|
||||||
mostPosts(gibberish);
|
|
||||||
};
|
|
||||||
assert.throws(failedCall, Error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
const { test } = require('node:test')
|
|
||||||
const assert = require('node:assert')
|
|
||||||
|
|
||||||
const reverse = require('../src/utils.js').reverse
|
|
||||||
|
|
||||||
test('reverse of a', () => {
|
|
||||||
const result = reverse('a')
|
|
||||||
|
|
||||||
assert.strictEqual(result, 'a')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('reverse of react', () => {
|
|
||||||
const result = reverse('react')
|
|
||||||
|
|
||||||
assert.strictEqual(result, 'tcaer')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('reverse of saippuakauppias', () => {
|
|
||||||
const result = reverse('saippuakauppias')
|
|
||||||
|
|
||||||
assert.strictEqual(result, 'saippuakauppias')
|
|
||||||
})
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
const { test, describe } = require("node:test");
|
|
||||||
const assert = require("node:assert");
|
|
||||||
const { totalLikes } = require("../src/utils");
|
|
||||||
|
|
||||||
describe("total likes ", () => {
|
|
||||||
const posts = [
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 5,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_id: "5a422aa71b54a676234d17f8",
|
|
||||||
title: "Go To Statement Considered Harmful",
|
|
||||||
author: "Edsger W. Dijkstra",
|
|
||||||
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
|
|
||||||
likes: 2,
|
|
||||||
__v: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const emptyArray = [];
|
|
||||||
|
|
||||||
const gibberish = "asdaSd123asd";
|
|
||||||
|
|
||||||
test("counts likes properly", () => {
|
|
||||||
assert.strictEqual(totalLikes(posts), 7);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("works fine with empty array", () => {
|
|
||||||
assert.strictEqual(totalLikes(emptyArray), 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("fails with gibberish input", () => {
|
|
||||||
const failedCall = () => {
|
|
||||||
totalLikes(gibberish);
|
|
||||||
};
|
|
||||||
assert.throws(failedCall, Error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
Exercises:
|
|
||||||
* [X] 4.1
|
|
||||||
* [X] 4.2
|
|
||||||
* [X] 4.3
|
|
||||||
* [X] 4.4
|
|
||||||
* [X] 4.5
|
|
||||||
* [X] 4.6
|
|
||||||
* [X] 4.7
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue