Changelog
-
+
- 2017-08: NoteHub 3.0 released.
- 2016-08: Syntax highlighting for code blocks added (thanks to Maciej).
- 2016-03: Note deletion feature added.
- 2015-10: NoteHub rewritten in Node.js. @@ -34,7 +35,7 @@
diff --git a/Makefile b/Makefile deleted file mode 100644 index 1db5a30..0000000 --- a/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -push: - git push prod - git push origin diff --git a/README.md b/README.md index 69e04aa..dcb61f4 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,12 @@ # README -## About - -[NoteHub](https://www.notehub.org) is a free and hassle-free pastebin for one-off markdown publishing and was implemented as a one-app-one-language [experiment](https://notehub.org/ikqz8). - -## Implementation - -NoteHub's implementation aims for ultimate simplicity and performance. +> "Make every detail perfect and limit the number of details to perfect." +> — _Jack Dorsey_ -### Design +## About -1. At a request, the server first checks, if a note is already rendered and is present in the LRU cache. - (a) If _yes_, it return the rendered HTML code and increases the views counter. - (b) Otherwise, the note is retrieved from the DB, rendered and put into the LRU cache; the views counter will be increased. -2. The rendering of note pages: there are HTML file tempates with placeholders, which will be trivially filled with replacements. -3. The LRU cache holds the rendered HTML for the most popular notes, which makes their access a static O(1) operation without any DB I/O. -4. The server keeps corresponding models for all notes in the cache for statistics updates. These models are persisted every 5 minutes to the DB. +Dead simple hosting for markdown notes. ## Installation & Deployment -To run NoteHub as a standalone version, execute: - -1. `git clone https://github.com/chmllr/NoteHub.git` -2. `npm install` -3. `npm start` - -This starts a NoteHub instance on port 3000. \ No newline at end of file +TBD diff --git a/api_spec.js b/api_spec.js deleted file mode 100644 index a5a7f2d..0000000 --- a/api_spec.js +++ /dev/null @@ -1,234 +0,0 @@ -var frisby = require('frisby'); -var md5 = require('md5'); - -frisby.create('Landing page') - .get('http://localhost:3000/') - .expectStatus(200) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectBodyContains('Hassle-free') - .toss(); - -frisby.create('Open note page') - .get('http://localhost:3000/new') - .expectStatus(200) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectBodyContains('Terms of Service') - .toss(); - -frisby.create('Open TOS') - .get('http://localhost:3000/TOS') - .expectStatus(200) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectBodyContains('Site Terms of Use Modifications') - .toss(); - -frisby.create('Incurrect URL') - .get('http://localhost:3000/abcdef') - .expectStatus(404) - .expectBodyContains('Not found') - .toss(); - -frisby.create('Invalid posting') - .post('http://localhost:3000/note') - .expectStatus(400) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectBodyContains('Bad request') - .toss(); - -let testNote = 'This is a test note'; - -frisby.create('Invalid posting 2') - .post('http://localhost:3000/note', { - action: 'POST', - note: testNote - }) - .expectStatus(400) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectBodyContains('Bad request') - .toss(); - -frisby.create('Invalid posting 3') - .post('http://localhost:3000/note', { - action: 'POST', - session: md5('new'), - signature: 'assdss', - note: testNote - }) - .expectStatus(400) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectBodyContains('Signature mismatch') - .toss(); - -frisby.create('Valid posting') - .post('http://localhost:3000/note', { - action: 'POST', - session: md5('new'), - signature: md5(md5('new') + testNote), - password: '', - note: testNote - }) - .expectStatus(302) - .expectBodyContains('Found. Redirecting to') - .expectHeaderContains('content-type', 'text/plain; charset=utf-8') - .after(function(err, res, body) { - let noteId = body.replace('Found. Redirecting to /', ''); - frisby.create('Read posted note') - .get('http://localhost:3000/' + noteId) - .expectStatus(200) - .expectBodyContains(testNote) - .after((err, res, body) => { - frisby.create('Illegal note editing attempt with empty password') - .post('http://localhost:3000/note', { - id: noteId, - action: 'UPDATE', - session: md5('new'), - signature: md5(md5('new') + testNote+'!!!'), - note: testNote + '!!!', - password: '' - }) - .expectStatus(400) - .expectBodyContains('Password is wrong') - .toss(); - }) - .after((err, res, body) => { - frisby.create('Illegal note editing attempt') - .post('http://localhost:3000/note', { - id: noteId, - action: 'UPDATE', - session: md5('new'), - signature: md5(md5('new') + testNote+'!!!'), - note: testNote + '!!!', - password: 'aaabbb' - }) - .expectStatus(400) - .expectBodyContains('Password is wrong') - .toss(); - - }) - .toss(); - }) - .toss(); - -frisby.create('Valid posting, editing and removal') - .post('http://localhost:3000/note', { - action: 'POST', - session: md5('new'), - signature: md5(md5('new') + testNote), - password: 'aabbcc', - note: testNote - }) - .expectStatus(302) - .expectBodyContains('Found. Redirecting to') - .expectHeaderContains('content-type', 'text/plain; charset=utf-8') - .after(function(err, res, body) { - var noteId = body.replace('Found. Redirecting to /', ''); - frisby.create('Export posted note') - .get('http://localhost:3000/' + noteId + '/export') - .expectStatus(200) - .expectHeaderContains('content-type', 'text/plain; charset=utf-8') - .expectBodyContains(testNote) - .toss(); - frisby.create('Read posted note') - .get('http://localhost:3000/' + noteId) - .expectStatus(200) - .expectBodyContains(testNote) - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .after((err, res, body) => { - frisby.create('Unauthorized note editing attempt') - .post('http://localhost:3000/note', { - id: noteId, - action: 'UPDATE', - session: md5('new'), - signature: md5(md5('new') + testNote+'!!!'), - note: testNote + '!!!', - password: 'abbcc' - }) - .expectStatus(400) - .expectBodyContains('Password is wrong') - .toss(); - }) - .after((err, res, body) => { - frisby.create('Valid note editing attempt') - .post('http://localhost:3000/note', { - id: noteId, - action: 'UPDATE', - session: md5('new'), - signature: md5(md5('new') + 'Changed!'), - note: 'Changed!', - password: 'aabbcc' - }) - .expectStatus(302) - .after((err, res, body) => { - frisby.create('Read changed note') - .get('http://localhost:3000/' + noteId) - .expectStatus(200) - .expectBodyContains('Changed!') - .toss(); - }) - .after((err, res, body) => { - frisby.create('Delete posted note') - .post('http://localhost:3000/note',{ - id: noteId, - button: 'Delete', - action: 'UPDATE', - session: md5('new'), - signature: md5(md5('new') + 'Changed!'), - note: 'Changed!', - password: 'aabbcc' - }) - .expectStatus(200) - .expectBodyContains('Note deleted') - .toss(); - }) - .toss(); - }) - .toss(); - frisby.create('Read stats of posted note') - .expectStatus(200) - .get('http://localhost:3000/' + noteId).toss(); - frisby.create('Read stats of posted note') - .expectStatus(200) - .get('http://localhost:3000/' + noteId).toss(); - frisby.create('Read stats of posted note') - .expectStatus(200) - .get('http://localhost:3000/' + noteId).toss(); - frisby.create('Read stats of posted note') - .get('http://localhost:3000/' + noteId + '/stats') - .expectHeaderContains('content-type', 'text/html; charset=utf-8') - .expectStatus(200) - .expectBodyContains('Statistics') - .expectBodyContains('