Compare commits

..

No commits in common. "3f8e8479d0ba30e082cf04c745a18b5a654ee176" and "a108d90a3d1dcd78f7f83edf3c9c3c2a88665e91" have entirely different histories.

22 changed files with 62 additions and 8162 deletions

View File

@ -1,3 +0,0 @@
footer.html
table.html

View File

@ -1,43 +0,0 @@
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 => `<tr><td>${article.title}</td><td>${article.link}</td></tr>`
)
.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);
}
});

View File

@ -1,22 +0,0 @@
module.exports = listString =>
`
<!DOCTYPE html>
<html>
<body>
<h2>Haxor Newz</h2>
<h3>"uber l337"</h3>
<table>
<thead>
<th>Title</th>
<th>Link</th>
</thead>
${listString}
<tfoot>
ATTACK!
</tfoot>
</table>
<footer>&#9398; anarchy planet</footer>
</body>
</html>
`;

View File

@ -1,20 +0,0 @@
const router = require('express').Router();
module.exports = router;
router.use('/items', require('./items'));
router.use('/articles', require('./articles'));
router.get('/', async (req, res, next) => {
try {
res.send('/n-------/nHello from Express!/n--------/n');
} catch (err) {
next(err);
}
});
router.use((req, res, next) => {
const error = new Error('Not Found!!!!!!!');
error.status = 404;
next(error);
});

View File

@ -1,24 +0,0 @@
const router = require('express').Router();
const { Item } = require('../db/models');
module.exports = router;
router.get('/', async (req, res, next) => {
try {
const items = await Item.findAll();
res.status(201).send(items);
} catch (err) {
next(err);
}
});
router.post('/', async (req, res, next) => {
try {
const item = await Item.create(req.body);
res.status(201).json(item);
} catch (err) {
next(err);
}
});

View File

@ -1,13 +0,0 @@
const router = require('express').Router();
module.exports = router;
// what you will hit at /api/robots
router.get('/', async (req, res, next) => {
try {
console.log('NSA was here');
res.status(201).send('FUCK YOU NSA\n');
} catch (err) {
next(err);
}
});

View File

@ -1,26 +0,0 @@
const ascii = String.raw`
. .
* . . . . *
. . . . . .
o . .
. . . .
0 . anarchy
. . , planet , ,
. \ . .
. . \ ,
. o . . .
. . . \ , .
#\##\# . .
# #O##\### .
. . #*# #\##\### .
. ##*# #\##\## .
. . ##*# #o##\# .
. *# #\# . .
\ . .
____^/\___^--____/\____O______________/\/\---/\___________--
/\^ ^ ^ ^ ^^ ^ '\ ^ ^
-- - -- - - --- __ ^
-- __ ___-- ^ ^`;
module.exports = ascii;

View File

@ -1,26 +0,0 @@
const Sequelize = require('sequelize');
const pkg = require('../package.json');
const databaseName =
pkg.name + (process.env.NODE_ENV === 'test' ? '-test' : '');
const createDB = () => {
const db = new Sequelize(
process.env.DATABASE_URL || `postgres://localhost:5432/${databaseName}`,
{
logging: false,
operatorsAliases: false
}
);
return db;
};
const db = createDB();
module.exports = db;
// This is a global Mocha hook used for resource cleanup.
// Otherwise, Mocha v4+ does not exit after tests.
if (process.env.NODE_ENV === 'test') {
after('close database connection', () => db.close());
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
const db = require('./db');
// register models
require('./models');
module.exports = db;

View File

@ -1,14 +0,0 @@
const Sequelize = require('sequelize');
const db = require('../db');
const Article = db.define('articles', {
title: {
type: Sequelize.STRING,
allowNull: false
},
link: {
type: Sequelize.STRING
}
});
module.exports = Article;

View File

@ -1,4 +0,0 @@
const Item = require('./item');
const Article = require('./article');
module.exports = { Item, Article };

View File

@ -1,11 +0,0 @@
const Sequelize = require('sequelize');
const db = require('../db');
const Item = db.define('items', {
name: {
type: Sequelize.STRING,
allowNull: false
}
});
module.exports = Item;

View File

@ -1,27 +0,0 @@
const db = require('../db');
const { Article } = require('./models');
const testArticle = {
title: 'read desert',
link: 'https://readdesert.org'
};
console.log(Article);
async function runSeed() {
await db.sync({ force: true });
console.log('db synced!');
console.log('seeding...');
try {
await Article.create(testArticle);
console.log('seeded successfully');
} catch (err) {
console.error(err);
process.exitCode = 1;
} finally {
console.log('closing db connection');
await db.close();
console.log('db connection closed');
}
}
runSeed();

View File

@ -1,47 +0,0 @@
const fetch = require('node-fetch');
// implemented from: https://github.com/HackerNews/API
const HN_PREFIX = 'https://hacker-news.firebaseio.com/v0/';
const TOP_STORIES = 'topstories';
const ITEM = 'item';
function hnFetch(type, id = '') {
const url = id
? `${HN_PREFIX}${type}/${id}.json`
: `${HN_PREFIX}${type}.json`;
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (!isStatusOk(res.status)) {
throw res;
}
return res.json();
})
.then(res => res)
.catch(error => console.error(error));
}
function isStatusOk(statusCode) {
return statusCode === 200 || statusCode === 304;
}
async function main() {
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;
})
);
}
main();

69
index.js Executable file → Normal file
View File

@ -1,41 +1,42 @@
const express = require('express'); const fetch = require("node-fetch");
const path = require('path');
const morgan = require('morgan');
const ascii = require('./ascii');
const db = require('./db');
const app = express(); // implemented from: https://github.com/HackerNews/API
const port = process.env.PORT || 1337;
db.authenticate() const HN_PREFIX = "https://hacker-news.firebaseio.com/v0/";
.then(() => {
console.log('Connection has been established successfully.'); const TOP_STORIES = "topstories";
const ITEM = "item";
function hnFetch(type, id = "") {
const url = id
? `${HN_PREFIX}${type}/${id}.json`
: `${HN_PREFIX}${type}.json`;
return fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}) })
.catch(err => { .then(res => {
console.error('Unable to connect to the database:', err); if (!isStatusOk(res.status)) {
}); throw res;
}
return res.json();
})
.then(res => res)
.catch(error => console.error(error));
}
app.use(morgan('tiny')); function isStatusOk(statusCode) {
return statusCode === 200 || statusCode === 304;
// body parsing middleware }
app.use(express.json()); async function main() {
app.use(express.urlencoded({ extended: true })); const storyIds = await hnFetch(TOP_STORIES);
app.use(require('body-parser').text()); const stories = await Promise.all(
app.use('/api', require('./api')); storyIds.slice(0, 20).map(storyId => hnFetch(ITEM, storyId))
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, 'public', 'articles.html'))
); );
// error handling endware console.log(stories.map(story => { delete story.kids; return story; }));
app.use((err, req, res, next) => { }
console.error(err);
console.error(err.stack);
res.status(err.status || 500).send(err.message || 'Internal server error.');
next();
});
app.listen(port, () => { main();
console.log(`\n${ascii}\n`);
console.log(`Doin' haxor stuff on port ${port}`);
});

View File

@ -1,33 +1,37 @@
* Hacker News Clone - CLI Version * Hacker News Clone - CLI Version
** README
The MVP of this project is a clone of https://news.ycombinator.com but in CLI. The MVP of this project is a clone of https://news.ycombinator.com but in CLI. A user should be able to log in from the command line and be presented with a list of stories, along with a 'menu bar' that has the options in HN: news, comments, ask, show, jobs, submit (we will likely not use all of these options, but let's keep it as a clone for now).
** TODOs
A user should be able to: ** notes
- read a list of articles in the database from the command line *** features
- create a new story by posting a link and a title **** voting
- vote up or down on a story ***** registration
** voting
*** registration
required to comment (?) required to comment (?)
*** search ***** search
by popularity, date. I find it effective. by popularity, date. I find it effective.
*** threaded collapsible comments ***** threaded collapsible comments
- All threads threaded and collapsible. maxed by default. each can be minimized individually, collapsing all contained comments. - All threads threaded and collapsible. maxed by default. each can be minimized individually, collapsing all contained comments.
- main threads sorted by quality, replies chronological (?), - main threads sorted by quality, replies chronological (?),
- poor quality comments remain visible but dimmed according to how downvoted - poor quality comments remain visible but dimmed according to how downvoted
*** user karma ***** user karma
- users have karma - users have karma
- user post/comment history can be seen by clicking on their profile. - user post/comment history can be seen by clicking on their profile.
*** voting ***** voting
regiistration required regiistration required
min karma required for downvoting (comments only?) min karma required for downvoting (comments only?)
*** sort algorithms (see note below) ***** sort algorithms (see note below)
- posts sorted by ratio of upvotes / newness / user karma / voodoo - posts sorted by ratio of upvotes / newness / user karma / voodoo
*** user control of search / sort options ***** user control of search / sort options
- users can view HN sorted view, chrono posts, chrono comments, (?) - users can view HN sorted view, chrono posts, chrono comments, (?)
*** 'dead' (shadowbanned) profiles ***** 'dead' (shadowbanned) profiles
These are profiles where the user doesn't know they are 'shadowbanned', so they continue to post but can't tell that no one else can see it. These are profiles where the user doesn't know they are 'shadowbanned', so they continue to post but can't tell that no one else can see it.
- [[https://news.ycombinator.com/newsguidelines.html][explicit rules]] and culture to encourage / discourage certain content - [[https://news.ycombinator.com/newsguidelines.html][explicit rules]] and culture to encourage / discourage certain content
*** User Stories
**** MVP
- landing page has a list of articles
- submit a story by pasting a link
**** logging in

6501
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,54 +3,16 @@
"version": "1.0.0", "version": "1.0.0",
"description": "TODO", "description": "TODO",
"main": "index.js", "main": "index.js",
"author": "anarchyplanet", "scripts": {
"license": "&#9398;", "test": "mocha ."
"bugs": {
"url": "https://irc.anarchyplanet.org/git/notnull/server/issues"
}, },
"homepage": "irc.anarchyplanet.org",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "ssh://git@irc.anarchyplanet.org:2222/notnull/hacker-news-cli.git" "url": "ssh://git@irc.anarchyplanet.org:2222/notnull/hacker-news-cli.git"
}, },
"scripts": { "author": "",
"test": "mocha .", "license": "MIT",
"seed": "node db/seed.js",
"start": "nodemon index"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
},
"dependencies": { "dependencies": {
"axios": "^0.18.0", "node-fetch": "^2.3.0"
"body-parser": "^1.18.3",
"concurrently": "^4.0.1",
"express": "^4.16.4",
"http-proxy-middleware": "^0.19.0",
"morgan": "^1.9.1",
"node-fetch": "^2.3.0",
"nodemon": "^1.18.9",
"pg": "^7.5.0",
"sequelize": "^4.39.1"
},
"devDependencies": {
"eslint": "^5.3.0",
"eslint-config-prettier": "^4.0.0",
"eslint-config-recommended": "^4.0.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-react": "^7.12.4",
"husky": "^1.3.1",
"lint-staged": "^8.1.3",
"prettier": "^1.16.4"
} }
} }

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<h2>Haxor Newz</h2>
<h3>"uber l337"</h3>
<form action="" method="POST">
Title:<br />
<input type="text" name="title" value="" /> <br />
Link:<br />
<input type="text" name="link" value="" /> <br />
</form>
<p>&#9398; anarchy planet</p>
</body>
</html>

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<h2>Haxor Newz</h2>
<h3>"uber l337"</h3>
<form action="" method="POST">
Title:<br />
<input type="text" name="title" value="" /> <br />
Link:<br />
<input type="text" name="link" value="" /> <br />
</form>
<footer>&#9398; anarchy planet</footer>
</body>
</html>