diff --git a/api/articles.js b/api/articles.js index f124858..0eb2cc3 100644 --- a/api/articles.js +++ b/api/articles.js @@ -1,43 +1,40 @@ -const router = require('express').Router(); -const { Article } = require('../db/models'); -const buildPage = require('./buildPage'); +const router = require('express').Router() +const { Article } = require('../db/models') +const buildPage = require('../scripts/buildPage') +const buildTable = require('../scripts/buildArticleTable') -module.exports = router; +module.exports = router router.get('/', async (req, res, next) => { try { - const articles = await Article.findAll(); - const tbl = articles - .map( - article => `${article.title}${article.link}` - ) - .join(); - const page = buildPage(tbl); - console.log(page); - res.status(201).send(page); + const articles = await Article.findAll() + const tbl = buildTable(articles) + const page = buildPage(tbl) + console.log('REEEEEEEEEEEEEEEEEEE\n', page, tbl) + res.status(201).send(page) } catch (err) { - next(err); + next(err) } -}); +}) router.get('/:id', async (req, res, next) => { try { - const article = await Article.findById(req.params.id); - console.log(article.title); - console.log(`by: ${article.author}`); - console.log(article.text); - res.status(201).send(article); + const article = await Article.findById(req.params.id) + console.log(article.title) + console.log(`by: ${article.author}`) + console.log(article.text) + res.status(201).send(article) } catch (err) { - next(err); + next(err) } -}); +}) router.post('/', async (req, res, next) => { - const body = req.body; + const body = req.body try { - const article = await Article.create(body); - res.redirect(article.id); + const article = await Article.create(body) + res.redirect(article.id) } catch (err) { - next(err); + next(err) } -}); +}) diff --git a/api/comments.js b/api/comments.js new file mode 100644 index 0000000..6bbdf9a --- /dev/null +++ b/api/comments.js @@ -0,0 +1,27 @@ +const router = require('express').Router() +const { Comment } = require('../db/models') +const buildPage = require('../scripts/buildPage') +module.exports = router + +router.get('/', async (req, res, next) => { + try { + const comments = await Comment.findAll({ + attributes: ['id', 'title', 'content', 'userId', 'parentId'], + }) + const page = buildPage( + res.status(201).send() + } catch (err) { + next(err) + } +}) + +router.post('/', async (req, res, next) => { + const newComment = req.body // good sanitization + + try { + const comment = await Comment.create(newComment) + res.redirect('http://localhost:1337') + } catch (err) { + next(err) + } +}) diff --git a/api/index.js b/api/index.js index cbc032c..8fc2cd9 100755 --- a/api/index.js +++ b/api/index.js @@ -1,20 +1,21 @@ -const router = require('express').Router(); +const router = require('express').Router() -module.exports = router; +module.exports = router -router.use('/items', require('./items')); -router.use('/articles', require('./articles')); +router.use('/items', require('./items')) +router.use('/articles', require('./articles')) +router.use('/comments', require('./comments')) router.get('/', async (req, res, next) => { try { - res.send('/n-------/nHello from Express!/n--------/n'); + res.send('/n-------/nHello from Express!/n--------/n') } catch (err) { - next(err); + next(err) } -}); +}) router.use((req, res, next) => { - const error = new Error('Not Found!!!!!!!'); - error.status = 404; - next(error); -}); + const error = new Error('Not Found!!!!!!!') + error.status = 404 + next(error) +}) diff --git a/api/users.js b/api/users.js new file mode 100644 index 0000000..ae0ef4f --- /dev/null +++ b/api/users.js @@ -0,0 +1,13 @@ +const router = require('express').Router() +const { User } = require('../db/models') + +module.exports = router + +router.get('/', async (req, res, next) => { + try { + const users = await User.findAll({ include: User }) + res.status(201).json(users) + } catch (err) { + next(err) + } +}) diff --git a/db/db.js b/db/db.js index 0d4671c..dd58291 100755 --- a/db/db.js +++ b/db/db.js @@ -7,8 +7,7 @@ const createDB = () => { const db = new Sequelize( process.env.DATABASE_URL || `postgres://localhost:5432/${databaseName}`, { - logging: false, - operatorsAliases: false + operatorsAliases: false, } ) return db diff --git a/db/index.js b/db/index.js index 98b7935..107371a 100755 --- a/db/index.js +++ b/db/index.js @@ -1,28 +1,14 @@ const db = require('./db') -const {Article, Vote, User} = require('./models'); -// sigh -// I am using Sequelize as an ORM for the database. -// It has its own syntax for defining the relations -// in the database. Something like the following: -Article.belongsTo(User) -User.hasMany(Article) - -Article.hasMany(Vote) -Vote.belongsTo(Article) - -Vote.belongsTo(User) -User.hasMany(Vote) - // the questions are: -// 1. how to store votes in the database? as a count on the article? this would be less accurate but ok for the beginning <- I am not a fan of this approach -// 2. what votes do we count? (anon, per ip address, cookies?) to build relations between votes we need a concept of users based identification <- yep! +// 1. how to store votes in the database? as a count on the article? this would be less accurate but ok for the beginning <- I am not a fan of this approach +// 2. what votes do we count? (anon, per ip address, cookies?) to build relations between votes we need a concept of users based identification <- yep! // 3. also downvotes? <- so I think to start we shoudl copy what HN does agreed :) // TODO figure out how HN implements votes (I think non-registered voters can't vote for example) // re: users: I can implement some hacky user auth to start with... or maybe that's something we delegate to rw (totally_not_fb) -// hn voting +// hn voting // regiistration required -// min karma required for downvoting (comments only?) +// min karma required for downvoting (comments only?) // so we could start writing tickets at this point ... ? makes sense // view content: https://irc.anarchyplanet.org/git/notnull/hacker-news-cli/issues/4 // post content: https://irc.anarchyplanet.org/git/notnull/hacker-news-cli/issues/3 diff --git a/db/models/index.js b/db/models/index.js index 08e6eeb..9c7c540 100755 --- a/db/models/index.js +++ b/db/models/index.js @@ -1,19 +1,19 @@ const Item = require('./item') const Article = require('./article') const Comment = require('./comment') -//const User = require('./user') +const User = require('./user') -Article.hasMany(Comment) //puts postId on Comment +Article.hasMany(Comment) // allows for addComment Comment.belongsTo(Article) -//User.hasMany(Article) //puts userId on Post, creates instance method 'user.getPosts()' -//Article.belongsTo(User) // creates instance method 'post.getUser()'' +User.hasMany(Article) +Article.belongsTo(User) // allows for setUser -//User.hasMany(Comment) //puts userId on Comment -//Comment.belongsTo(User) //puts userId on Comment +User.hasMany(Comment) +Comment.belongsTo(User) -// TODO -//Comment.belongsTo(Comment, { as: 'parent' }) -//Comment.hasMany(Comment, { as: { singular: 'reply', plural: 'replies' } }) +// i understand more now: parent must be set instead of reply. -module.exports = { Item, Article, Comment } +Comment.belongsTo(Comment, { as: 'parent' }) // setParent + +module.exports = { Item, Article, Comment, User } diff --git a/db/models/user.js b/db/models/user.js index 5ce8164..fe3ba13 100644 --- a/db/models/user.js +++ b/db/models/user.js @@ -11,22 +11,21 @@ const User = db.define('user', { email: { type: Sequelize.STRING, unique: true, - allowNull: false }, firstName: { - type: Sequelize.STRING + type: Sequelize.STRING, }, lastName: { - type: Sequelize.STRING + type: Sequelize.STRING, }, username: { type: Sequelize.STRING, unique: true, - allowNull: false + allowNull: false, }, imageUrl: { type: Sequelize.STRING, - defaultValue: 'novatore.jpg' + defaultValue: 'novatore.jpg', }, password: { @@ -35,7 +34,7 @@ const User = db.define('user', { // This is a hack to get around Sequelize's lack of a "private" option. get() { return () => this.getDataValue('password') - } + }, }, salt: { type: Sequelize.STRING, @@ -43,11 +42,8 @@ const User = db.define('user', { // This is a hack to get around Sequelize's lack of a "private" option. get() { return () => this.getDataValue('salt') - } + }, }, - googleId: { - type: Sequelize.STRING - } }) module.exports = User diff --git a/db/seed.js b/db/seed.js index cbb9025..5727ddf 100755 --- a/db/seed.js +++ b/db/seed.js @@ -1,41 +1,63 @@ -const db = require("../db"); -const { Article, Comment, User } = require("./models"); -// WHYYYYYYY -const testArticle = { - title: "read desert", - link: "https://readdesert.org" -}; +const db = require('../db') +const { Article, Comment, User } = require('./models') +const testArticle = { + title: 'read desert', + link: 'https://readdesert.org', +} + +const testArticle2 = { + title: 'the best place ever', + link: 'https://irc.anarchyplanet.org', +} const testComment = { - title: "best essay ever", - content: "read the sand book already!" -}; + title: 'best essay ever', + content: 'read the sand book already!', +} + +const testReply = { + title: 'u r so dumb', + content: 'i hate anews :P', +} + +const testReply2 = { + title: 'best essay ever', + content: 'read the sand book already!', +} const testUser = { - nick: "nn" -}; + username: 'nn', +} async function runSeed() { - await db.sync({ force: true }); - console.log("db synced!"); - console.log("seeding..."); + await db.sync({ force: true }) + console.log('db synced!') + console.log('seeding...') try { - const article = await Article.create(testArticle); + const article = await Article.create(testArticle) - const user = await User.create(testUser); - const c1 = await Comment.create(testComment); - c1.addUser(user); - article.addUser(user); - article.addComment(c1); - console.log("seeded successfully"); + const user = await User.create(testUser) + const c1 = await Comment.create(testComment) + const c2 = await Comment.create(testReply) + const c3 = await Comment.create(testReply2) + await article.setUser(user) + await c1.setUser(user) + await c2.setUser(user) + await article.addComment(c1) + + await c2.setParent(c1) + await c3.setParent(c2) + // await c2.setParent(c1) + + console.log('seeded successfully') } catch (err) { - console.error(err); - process.exitCode = 1; + console.error(err) + process.exitCode = 1 } finally { - console.log("closing db connection"); - await db.close(); - console.log("db connection closed"); + console.log('closing db connection') + await db.close() + console.log('db connection closed') } } -runSeed(); +runSeed() diff --git a/hn-client.js b/hn-client.js index 8771a6f..8f79f7e 100644 --- a/hn-client.js +++ b/hn-client.js @@ -1,47 +1,45 @@ -const fetch = require('node-fetch'); +const fetch = require('node-fetch') // implemented from: https://github.com/HackerNews/API -const HN_PREFIX = 'https://hacker-news.firebaseio.com/v0/'; +const HN_PREFIX = 'https://hacker-news.firebaseio.com/v0/' -const TOP_STORIES = 'topstories'; -const ITEM = 'item'; +const TOP_STORIES = 'topstories' +const ITEM = 'item' function hnFetch(type, id = '') { - const url = id - ? `${HN_PREFIX}${type}/${id}.json` - : `${HN_PREFIX}${type}.json`; + const url = id ? `${HN_PREFIX}${type}/${id}.json` : `${HN_PREFIX}${type}.json` return fetch(url, { method: 'GET', headers: { - 'Content-Type': 'application/json' - } + 'Content-Type': 'application/json', + }, }) .then(res => { if (!isStatusOk(res.status)) { - throw res; + throw res } - return res.json(); + return res.json() }) .then(res => res) - .catch(error => console.error(error)); + .catch(error => console.error(error)) } function isStatusOk(statusCode) { - return statusCode === 200 || statusCode === 304; + return statusCode === 200 || statusCode === 304 } async function main() { - const storyIds = await hnFetch(TOP_STORIES); + const storyIds = await hnFetch(TOP_STORIES) const stories = await Promise.all( storyIds.slice(0, 20).map(storyId => hnFetch(ITEM, storyId)) - ); + ) console.log( stories.map(story => { - delete story.kids; - return story; + delete story.kids + return story }) - ); + ) } -main(); +main() diff --git a/index.js b/index.js index ef1e9bc..3de6c9a 100755 --- a/index.js +++ b/index.js @@ -22,10 +22,9 @@ app.use(express.json()) app.use(express.urlencoded({ extended: true })) app.use(require('body-parser').text()) app.use('/api', require('./api')) +app.use('/articles', require('./api/articles')) -app.get('*', (req, res) => - res.sendFile(path.resolve(__dirname, 'public', 'articles.html')) -) +app.get('*', (req, res) => res.send('try again.')) // error handling endware app.use((err, req, res, next) => { diff --git a/public/articles.js b/public/articles.js new file mode 100644 index 0000000..9d739a2 --- /dev/null +++ b/public/articles.js @@ -0,0 +1,43 @@ +const router = require('express').Router() +const { Article } = require('../db/models') +const buildPage = require('./buildPage') + +module.exports = router + +router.get('/', async (req, res, next) => { + try { + const articles = await Article.findAll() + const tbl = articles + .map( + article => `${article.title}${article.link}` + ) + .join() + const page = buildPage(tbl) + console.log(page) + res.status(201).send(page) + } catch (err) { + next(err) + } +}) + +router.get('/:id', async (req, res, next) => { + try { + const article = await Article.findById(req.params.id) + console.log(article.title) + console.log(`by: ${article.author}`) + console.log(article.text) + res.status(201).send(article) + } catch (err) { + next(err) + } +}) + +router.post('/', async (req, res, next) => { + const body = req.body + try { + const article = await Article.create(body) + res.redirect(article.id) + } catch (err) { + next(err) + } +}) diff --git a/public/form.html b/public/form.html new file mode 100644 index 0000000..cb6a411 --- /dev/null +++ b/public/form.html @@ -0,0 +1,21 @@ + + + + +

Haxor Newz

+

much l337. very inform.

+ +
+ title:
+ +
+ content:
+ +
+ +
+ +

Ⓐ anarchy planet

+ + + diff --git a/public/index.html b/public/old.html similarity index 100% rename from public/index.html rename to public/old.html diff --git a/scripts/buildArticleTable.js b/scripts/buildArticleTable.js new file mode 100644 index 0000000..f32b558 --- /dev/null +++ b/scripts/buildArticleTable.js @@ -0,0 +1,11 @@ +const buildTable = articles => + articles + .map( + article => + `${article.title}${ + article.content + }` + ) + .join() + +module.exports = buildTable diff --git a/api/buildPage.js b/scripts/buildPage.js similarity index 99% rename from api/buildPage.js rename to scripts/buildPage.js index fb76b89..6450d5c 100644 --- a/api/buildPage.js +++ b/scripts/buildPage.js @@ -19,4 +19,4 @@ module.exports = listString => -`; +` diff --git a/scripts/post.sh b/scripts/post.sh new file mode 100755 index 0000000..de9991f --- /dev/null +++ b/scripts/post.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# read user input: http://mywiki.wooledge.org/BashFAQ/078 +URL='http://localhost:1337/api/comments' + +read -p "title: " title +read -p "content: " content +DATA="{\"title\": \"$title\", \"content\": \"$content\"}" + +echo "Posting $DATA to $URL" +curl -H "Content-Type: application/json" -X POST -d "$DATA" "$URL" + +exit 0 + +#http://goinbigdata.com/using-curl-for-ad-hoc-testing-of-restful-microservices/ + +#https://stackoverflow.com/questions/7172784/how-to-post-json-data-with-curl-from-terminal-commandline-to-test-spring-rest