aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x_notes_cli.js167
-rw-r--r--notes.js173
-rwxr-xr-xnotes_cli.js341
3 files changed, 341 insertions, 340 deletions
diff --git a/_notes_cli.js b/_notes_cli.js
deleted file mode 100755
index 904f493..0000000
--- a/_notes_cli.js
+++ /dev/null
@@ -1,167 +0,0 @@
-const fs = require('fs')
-const { homedir } = require('os')
-
-let conf
-
-const https = require('https')
-const readline = require("readline")
-// const spawn = require('child_process').spawn
-
-const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout
-})
-
-const cl = (m, c) => console.log(c ? `\x1b[${c}m${m}\x1b[0m` : m)
-const cls = () => console.clear()
-
-const configPath = `${homedir}/.local/share/notes_cli`
-console.log(configPath)
-
-const setConf = (c, callback) => {
- fs.writeFile(configPath, JSON.stringify(c), function(err) {
- if(err) {
- cl(err, 32)
- cl('Error writting configuration file', 32)
- return null
- }
-
- conf = c
- return callback()
- })
-}
-
-const getConf = () => {
- fs.readFile(configPath, function(err, f){
- if (err) {
- cl('Configuration file not found', 33)
- return login()
- }
-
- try {
- const r = JSON.parse(f.toString())
-
- console.log(r)
-
- if (!r.session || !r.userId || !r.email || !r.list) {
- cl('Error parsing configuration', 31)
- process.exit(1)
- }
-
- conf = r
- return console.log('here handle config')
-
- //
-
- } catch (e) {
- cl('Error reading configuration', 31)
- process.exit(1)
- }
- })
-}
-
-const post = (path, data, callback) => {
- const dataString = JSON.stringify(data)
- const options = {
- hostname: 'apps.pruss.it',
- port: 443,
- path,
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Content-Length': dataString.length
- },
- timeout: 1000
- };
-
- const req = https.request(options, (res) => {
- let data = '';
-
- res.on('data', (chunk) => {
- data += chunk;
- });
-
- res.on('end', () => {
- return callback(JSON.parse(data), res.headers, res.statusCode);
- });
-
- }).on("error", () => {
- callback(null)
- });
-
- req.write(dataString);
- req.end();
-}
-
-const login = () => {
- cl('\nLogin to My Apps\n', 32)
- cl('+-------------------------------------------------------+\n'+
- '|Account can be created through apps.pruss.it website.|\n'+
- '|To quit type "q" and press enter. |\n'+
- '+-------------------------------------------------------+\n', 32)
- rl.resume()
- rl.question('Email: ', e => {
- if (e === 'q') {
- cl('\nExiting My Apps', 31)
- rl.close()
- process.exit(1)
- } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)) {
- cls()
- cl('\nNot a valid email address, try again.', 31)
- rl.pause()
- return login()
- }
-
- rl.stdoutMuted = true
-
- rl.question('Password: ', p => {
- if (p === 'q') {
- cl('\nExiting My Apps', 31)
- rl.close()
- process.exit(1)
- }
-
- rl.pause()
-
- post(
- '/api/login',
- {"email": e, "password": p},
- (o, h, s) => {
- if (!o || s !== 201) {
- cl('Could not log in, try again', 31)
- return login()
- }
-
- const {_id, email, isVerified, noteList} = o
- const session = h['set-cookie']
-
- if (!_id || !email || !noteList) {
- cl('Could not log in', 31)
- process.exit(1)
- } else if (!isVerified) {
- cl('User not verified.\nPlease first verify the user using apps.pruss.it', 32)
- return 1
- }
-
- const c = {userId: _id, email, list: noteList, session}
-
- setConf(c, () => {
- cl('Successfully saved configuration', 32)
- cl('saved config: ', conf)
- })
- })
- })
-
- rl._writeToOutput = function _writeToOutput(stringToWrite) {
- if (rl.stdoutMuted)
- rl.output.write("*")
- else
- rl.output.write(stringToWrite)
- };
-
- rl.history = rl.history.slice(1)
- })
-}
-
-cls()
-getConf()
diff --git a/notes.js b/notes.js
deleted file mode 100644
index 5aa7c2f..0000000
--- a/notes.js
+++ /dev/null
@@ -1,173 +0,0 @@
-const rl = require('readline');
-
-const list_mock = [
- '1',
- '2',
- '3',
- '4',
- '5',
- '6',
- '7',
- '8',
- '9',
- '10',
- '11',
- '12',
- '13',
- '14',
- '15',
- '16',
- '17',
- '18',
- '19',
- '20',
- '21',
- '22',
- '23',
- '24',
- '25',
- '26',
- '27',
- '28',
- '29',
- '30',
- '31',
- '32',
- '33',
- '34',
- '35',
- '36',
- '37',
- '38',
- '39',
- '40',
- '41',
- '42',
- '43',
- '44',
- '45',
- '46',
- '47',
- '48',
- '49',
- '50'
-]
-
-let active = 0; scroll = 0; draw = { t: 'p', v: ['Loading Notes App...'] }, appTitle = '', menu = ''
-const pr = t => process.stdout.write(t)
-const cls = () => console.clear()
-const cursor = {
- hide: () => pr('\u001B[?25l'),
- show: () => pr('\u001B[?25h')
-}
-
-// =========== DRAW APP =============
-
-const drawApp = () => {
- const lines = process.stdout.rows
- const columns = process.stdout.columns
- // process.stdout.write('\x1Bc')
- cls()
- for (var i = 0; i < lines - 1; i++) {
- const dist = t => [Math.floor((columns - t) / 2), Math.ceil((columns - t) / 2) - 2]
- switch(i){
- case 0:
- pr('╔'+'═'.repeat(columns - 2)+'╗')
- break
- case 1:
- pr('║'+' '.repeat(dist(appTitle.length)[0])+appTitle+' '.repeat(dist(appTitle.length)[1])+'║')
- break
- case 2:
- pr('╠'+'═'.repeat(columns - 2) +'╣')
- break
- case lines - 3:
- pr('╟'+'─'.repeat(columns - 2) +'╢')
- break
- case lines - 2:
- pr('║'+' '+menu.substring(0,columns-4)+' '.repeat(columns-menu.length-3)+'║')
- break
- default:
- const max = Math.max(...(draw.v.map(el => el.length)))
- if (draw.t === 'p') {
- if (i === (Math.floor((lines - draw.v.length) / 2) - 2)){
- pr('║'+' '.repeat(dist(max+4)[0])+'┌'+'─'.repeat(max+2)+'┐'+' '.repeat(dist(max+4)[1])+'║')
- } else if (i === (Math.floor((lines + draw.v.length) / 2) + 1)) {
- pr('║'+' '.repeat(dist(max+4)[0])+'└'+'─'.repeat(max+2)+'┘'+' '.repeat(dist(max+4)[1])+'║')
- } else if (i === (Math.floor((lines - draw.v.length) / 2) - 1) || i === (Math.floor((lines + draw.v.length) / 2))) {
- pr('║'+' '.repeat(dist(max+4)[0])+'│'+' '.repeat(max+2)+'│'+' '.repeat(dist(max+4)[1])+'║')
- } else if (i < (Math.floor((lines - draw.v.length) / 2) - 1) || (i > (Math.floor((lines + draw.v.length) / 2)))) {
- pr('║'+' '.repeat(columns - 2)+'║')
- } else {
- const n = i - (Math.floor((lines - draw.v.length) / 2))
- const t = draw.v[n]
- const s = [Math.floor((max+2-t.length) / 2), Math.ceil((max+2-t.length) / 2)]
- pr('║'+' '.repeat(dist(max+4)[0])+'│'+' '.repeat(s[0])+t+' '.repeat(s[1])+'│'+' '.repeat(dist(max+4)[1])+'║')
- }
- } else if (draw.t === 'l') {
- const l = draw.v[i-3+scroll] && draw.v[i-3+scroll].substring(0,columns-4)
-
- pr(l
- ? ('║'+(active===i-3+scroll?'\x1b[7m ':' ')+l+' '.repeat(columns-l.length-3)+'\x1b[0m║')
- : ('║'+' '.repeat(columns - 2)+'║')
- )
- }
- }
- }
-
- pr('╚'+'═'.repeat(columns - 2)+'╝')
-}
-
-// ============ GET KEY =================
-
-const getKey = () => {
- rl.emitKeypressEvents(process.stdin);
- process.stdin.setRawMode(true);
- process.stdin.on('keypress', (_, key) => {
- const lines = process.stdout.rows
- switch(key.name) {
- case 'up':
- case 'k':
- active > 0 && active--
- active < scroll && scroll--
- drawApp()
- break
- case 'down':
- case 'j':
- if (draw.t === 'l') {
- active < draw.v.length - 1 && active++
- active - scroll > lines - 7 && scroll++
- drawApp()
- }
- break
- case 'return':
- case 'o':
- // draw = { t: 'p', v: ['popup test'] }
- // draw = { t: 'p', v: ['popup test', 'aaaaaaa'] }
- draw = { t: 'p', v: ['popup test', '', `This will display note nr ${active + 1}.`] }
- drawApp()
- // process.stdout.write(draw.v[active]);
- break
- case 'q':
- cursor.show()
- console.clear()
- pr('Bye!\n\n')
- process.exit()
- default:
- }
- })
-}
-
-// ============ EXECUTION ================
-
-cls()
-cursor.hide()
-process.stdout.on('resize', drawApp);
-
-appTitle = "Notes App"
-menu = '[Q]uit [↓/j] Down [↑/k] Up [Enter/o] Open'
-draw = { t: 'l', v: list_mock }
-
-drawApp()
-getKey()
-
-
diff --git a/notes_cli.js b/notes_cli.js
new file mode 100755
index 0000000..be427d8
--- /dev/null
+++ b/notes_cli.js
@@ -0,0 +1,341 @@
+const fs = require('fs')
+const { homedir } = require('os')
+
+let conf
+
+const https = require('https')
+const readline = require("readline")
+// const spawn = require('child_process').spawn
+
+const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout
+})
+
+const cl = (m, c) => console.log(c ? `\x1b[${c}m${m}\x1b[0m` : m)
+const cls = () => console.clear()
+
+const configPath = `${homedir}/.local/share/notes_cli`
+
+// app view
+let active = 0; scroll = 0; draw = { t: 'p', v: () => ['Loading NOTES CLI...'] }, headers = () => ''
+const pr = t => process.stdout.write(t)
+const cursor = {
+ hide: () => pr('\u001B[?25l'),
+ show: () => pr('\u001B[?25h')
+}
+
+const fixedStr = (s, l) => s.length < l ? s.padEnd(l) : s.substring(0, l)
+const formatDate = d => d.replace('T',' ').replace(/\..*Z/, '')
+
+/* Views */
+const formatNote = note => {
+ const columns = process.stdout.columns
+ return columns > 72
+ ? `${fixedStr(note.title, columns - 45)} ${formatDate(note.created_at)} ${formatDate(note.updated_at)}`
+ : fixedStr(note.title, columns - note.title.length-2)
+}
+
+const showList = (notes, status) => {
+ if (status !== 200) {
+ cls()
+ return login('Session error')
+ }
+ headers = () => {
+ const columns = process.stdout.columns
+ return columns > 72
+ ? `${fixedStr(' Title', columns - 44)} Created at${' '.repeat(10)} Updated at ${' '.repeat(9)}`
+ : ` Title ${' '.repeat(columns - 9)}`
+ }
+ cursor.hide()
+ process.stdout.on('resize', drawApp);
+ draw = { t: 'l', v: () => notes.map(formatNote) }
+
+ drawApp()
+ getKey()
+}
+
+
+// =========== DRAW APP =============
+
+const drawApp = () => {
+ const lines = process.stdout.rows
+ const columns = process.stdout.columns
+ // process.stdout.write('\x1Bc')
+ cls()
+ for (var i = 0; i < lines - 1; i++) {
+ const dist = t => columns > t + 2 ? [Math.floor((columns - t) / 2), Math.ceil((columns - t) / 2) - 2] : [0, 0]
+ switch(i){
+ case 0:
+ pr('╔'+'═'.repeat(columns - 2)+'╗')
+ break
+ case 1:
+ pr('║'+' '.repeat(dist(conf.email.length+12)[0])+`NOTES CLI (${conf.email})`.substring(0, columns-2)+' '.repeat(dist(conf.email.length+12)[1])+'║')
+ break
+ case 2:
+ pr('╠'+'═'.repeat(columns - 2) +'╣')
+ break
+ case 3:
+ const h = headers()
+ pr('║'+(h || ' '.repeat(columns-2))+'║')
+ break
+ case 4:
+ pr('╟'+'─'.repeat(columns - 2) +'╢')
+ break
+ case lines - 3:
+ pr('╠'+'═'.repeat(columns - 2) +'╣')
+ break
+ case lines - 2:
+ const menu = '[Q]uit [↓/j] Down [↑/k] Up [Enter/o] Open'
+ pr('║'+' '+menu.substring(0,columns-4)+' '.repeat(columns-menu.length-3 > 0 ? columns-menu.length-3 : 1)+'║')
+ break
+ default:
+ const max = Math.max(...(draw.v().map(el => el.length)))
+ if (draw.t === 'p') {
+ if (i === (Math.floor((lines - draw.v().length) / 2) - 2)){
+ pr('║'+' '.repeat(dist(max+4)[0])+'┌'+'─'.repeat(max+2)+'┐'+' '.repeat(dist(max+4)[1])+'║')
+ } else if (i === (Math.floor((lines + draw.v().length) / 2) + 1)) {
+ pr('║'+' '.repeat(dist(max+4)[0])+'└'+'─'.repeat(max+2)+'┘'+' '.repeat(dist(max+4)[1])+'║')
+ } else if (i === (Math.floor((lines - draw.v().length) / 2) - 1) || i === (Math.floor((lines + draw.v().length) / 2))) {
+ pr('║'+' '.repeat(dist(max+4)[0])+'│'+' '.repeat(max+2)+'│'+' '.repeat(dist(max+4)[1])+'║')
+ } else if (i < (Math.floor((lines - draw.v().length) / 2) - 1) || (i > (Math.floor((lines + draw.v().length) / 2)))) {
+ pr('║'+' '.repeat(columns - 2)+'║')
+ } else {
+ const n = i - (Math.floor((lines - draw.v().length) / 2))
+ const t = draw.v()[n]
+ const s = [Math.floor((max+2-t.length) / 2), Math.ceil((max+2-t.length) / 2)]
+ pr('║'+' '.repeat(dist(max+4)[0])+'│'+' '.repeat(s[0])+t+' '.repeat(s[1])+'│'+' '.repeat(dist(max+4)[1])+'║')
+ }
+ } else if (draw.t === 'l') {
+ const l = draw.v()[i-5+scroll] && draw.v()[i-5+scroll].substring(0,columns-4)
+
+ pr(l
+ ? ('║'+(active===i-5+scroll?'\x1b[7m ':' ')+l+' '.repeat(columns-l.length-3)+'\x1b[0m║')
+ : ('║'+' '.repeat(columns - 2)+'║')
+ )
+ }
+ }
+ }
+
+ pr('╚'+'═'.repeat(columns - 2)+'╝')
+}
+
+// ============ GET KEY =================
+
+const getKey = () => {
+ readline.emitKeypressEvents(process.stdin);
+ process.stdin.setRawMode(true);
+ process.stdin.on('keypress', (_, key) => {
+ const lines = process.stdout.rows
+ switch(key.name) {
+ case 'up':
+ case 'k':
+ active > 0 && active--
+ active < scroll && scroll--
+ drawApp()
+ break
+ case 'down':
+ case 'j':
+ if (draw.t === 'l') {
+ active < draw.v().length - 1 && active++
+ active - scroll > lines - 7 && scroll++
+ drawApp()
+ }
+ break
+ case 'return':
+ case 'o':
+ draw = { t: 'p', v: () => ['popup test', '', `This will display note nr ${active + 1}.`] }
+ drawApp()
+ // process.stdout.write(draw.v[active]);
+ // openNote(active)
+ break
+ case 'q':
+ cursor.show()
+ console.clear()
+ pr('Bye!\n\n')
+ process.exit()
+ default:
+ }
+ })
+}
+
+
+/* Configuration */
+
+const setConf = (c, callback) => {
+ fs.writeFile(configPath, JSON.stringify(c), function(err) {
+ if(err) {
+ cl(err, 32)
+ cl('Error writting configuration file', 32)
+ return null
+ }
+
+ conf = c
+ return callback()
+ })
+}
+
+const getConf = () => {
+ fs.readFile(configPath, function(err, f){
+ if (err) {
+ return login()
+ }
+
+ try {
+ const r = JSON.parse(f.toString())
+
+ if (!r.session || !r.userId || !r.email || !r.list) {
+ return login('Error parsing configuration')
+ }
+
+ fetchList(r)
+ } catch (e) {
+ return login('Error reading configuration')
+ }
+ })
+}
+
+/* Login */
+
+const login = (error = '') => {
+ cl('\n Login to apps.pruss.it\n\n')
+ cl(' ┌'+'─'.repeat(50)+'┐\n'+' │'+' '.repeat(50)+'│\n'+' │ Account can be created on '+
+ 'apps.pruss.it website. │\n'+' │ To quit type "q" and press enter.'+' '.repeat(16)+'│\n'+
+ ' │'+' '.repeat(50)+'│\n'+' └'+'─'.repeat(50)+'┘\n', 32)
+ cl(' '+error+'\n', 31)
+ rl.resume()
+ rl.question(' Email: ', e => {
+ if (e === 'q') {
+ cl('\nExiting My Apps', 31)
+ rl.close()
+ process.exit(1)
+ } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)) {
+ cls()
+ rl.pause()
+ return login('Not a valid email address, try again.')
+ }
+
+ rl.stdoutMuted = true
+
+ rl.question(' Password: ', p => {
+ if (p === 'q') {
+ cl('\nExiting My Apps', 31)
+ rl.close()
+ process.exit(1)
+ }
+
+ rl.pause()
+
+ post(
+ '/api/login',
+ {"email": e, "password": p},
+ (o, s, h) => {
+ if (!o || s !== 201) {
+ rl.pause()
+ cls()
+ rl.stdoutMuted = false
+ return login('Could not log in, try again')
+ }
+
+ const {_id, email, isVerified, noteList} = o
+ const session = h['set-cookie']
+
+ if (!_id || !email || !noteList) {
+ cl('Could not log in', 31)
+ process.exit(1)
+ } else if (!isVerified) {
+ cl('User not verified.\nPlease first verify the user using apps.pruss.it', 32)
+ return 1
+ }
+
+ const c = {userId: _id, email, list: noteList, session}
+
+ setConf(c, () => {
+ cl('Successfully saved configuration', 32)
+ cl('saved config: ', conf)
+ })
+ })
+ })
+
+ rl._writeToOutput = function _writeToOutput(stringToWrite) {
+ if (rl.stdoutMuted)
+ rl.output.write("*")
+ else
+ rl.output.write(stringToWrite)
+ };
+
+ rl.history = rl.history.slice(1)
+ })
+}
+
+/* API */
+
+const fetchList = config => {
+ conf = config
+ drawApp()
+ get('/api/notes', showList, conf.session)
+}
+
+/* HTTPS METHODS */
+
+const get = (path, callback, cookie = '') => {
+ const options = {
+ hostname: 'apps.pruss.it',
+ port: 443,
+ path,
+ method: 'GET',
+ headers: {
+ 'Cookie': cookie,
+ },
+ };
+
+ const req = https.request(options, res => {
+ let data = '';
+
+ res.on('data', chunk => {
+ data += chunk
+ });
+
+ res.on('end', () => callback(JSON.parse(data), res.statusCode, res.headers));
+ });
+
+ req.on('error', () => {
+ callback(null)
+ });
+
+ req.end();
+}
+
+const post = (path, data, callback, cookie = '') => {
+ const dataString = JSON.stringify(data)
+ const options = {
+ hostname: 'apps.pruss.it',
+ port: 443,
+ path,
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Content-Length': dataString.length,
+ 'Cookie': cookie,
+ },
+ timeout: 1000
+ };
+
+ const req = https.request(options, (res) => {
+ let data = '';
+
+ res.on('data', chunk => {
+ data += chunk;
+ });
+
+ res.on('end', () => callback(JSON.parse(data), res.statusCode, res.headers));
+ }).on("error", () => {
+ callback(null)
+ });
+
+ req.write(dataString);
+ req.end();
+}
+
+cls()
+getConf()