From 67bdb9f84c0bc49f9647f8913d7655a82d70bfcf Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Sat, 18 May 2019 19:59:44 +0200 Subject: [PATCH] add bin/ and store secret in path --- bin/skl-auto-payslip.js | 27 ++++++++++++++++ default.nix | 3 ++ index.js | 70 ++++++++++++++++++++--------------------- package.json | 1 + 4 files changed, 66 insertions(+), 35 deletions(-) create mode 100755 bin/skl-auto-payslip.js create mode 100644 default.nix diff --git a/bin/skl-auto-payslip.js b/bin/skl-auto-payslip.js new file mode 100755 index 0000000..9b37e71 --- /dev/null +++ b/bin/skl-auto-payslip.js @@ -0,0 +1,27 @@ +#!/usr/bin/env node +const App = require('../index.js') +const sig = fn => + fn.toString().split('\n')[0].replace(/^async /, '').replace(/ \{/, '') + +const methods = App.prototype +// poor man's CLI +const [,, method, ...args] = process.argv +if (method in methods) { + if (args.length < methods[method].length) { + console.error("not enough arguments for method", sig(methods[method])) + } else { + App.authAll().then((auth) => { + const app = new App(auth) + app[method](...args) + }) + } +} else { + if (method && method != 'help') console.log("unknown subcall", method) + console.log("valid methods:") + for(const realMethod of Object.getOwnPropertyNames(methods)) { + if (realMethod == 'constructor') continue + if (methods[realMethod]) + console.log(" ", sig(methods[realMethod])) + } + process.exit(1) +} diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..3b0bf0e --- /dev/null +++ b/default.nix @@ -0,0 +1,3 @@ +with import {}; +with callPackage (fetchTarball https://github.com/serokell/nix-npm-buildpackage/archive/master.tar.gz) {}; +buildNpmPackage { src = ./.; } diff --git a/index.js b/index.js index 127d32b..192df08 100644 --- a/index.js +++ b/index.js @@ -8,19 +8,22 @@ const {promisify} = require('util') const readFile = promisify(fs.readFile) const base64url = require('base64url') const process = require('process') +const path = require('path') +const exec = promisify(require('child_process').exec) +const {spawn} = require('child_process') // If modifying these scopes, delete token.json. const SCOPES = ['https://www.googleapis.com/auth/drive','https://www.googleapis.com/auth/gmail.compose']; const USER = process.env['USER'] +const HOME = process.env['HOME'] const UserCapitalized = USER.charAt(0).toUpperCase() + USER.slice(1) const config = { - tokenPath: 'token.json', fileId: "1CqUglyFNoEWL0lx-e7arqUGOOZEYW__JjcwBmNaXE6E", template: `${UserCapitalized} ${(new Date()).getFullYear()} Template`, to: "billing@serokell.io", - destdir: "payslips" + destdir: `${HOME}/serokell/invoices/payslips` } async function authAll() { @@ -36,7 +39,7 @@ async function authorize(credentials) { // Check if we have previously stored a token. let token try { - token = await readFile(config.tokenPath) + token = await pass_get("skl-auto-payslip") } catch(e) { return getAccessToken(oAuth2Client) } @@ -53,6 +56,21 @@ async function ask(question) { rl.close() return answer } +function pass_insert(name, val) { + return new Promise((resolve, reject) => { + const pass = spawn("pass", ['insert', 'skl-auto-payslip', '-m'], {stdio: ['pipe', 'inherit', 'inherit']}) + pass.stdin.write(val) + pass.stdin.end() + pass.on('close', (code) => { + if (code != 0) reject(`pass exited with code ${code}`) + else { resolve() } + }) + }) +} +async function pass_get(name) { + const {stdout, stderr} = await exec("pass skl-auto-payslip") + return stdout +} async function getAccessToken(oAuth2Client) { const authUrl = oAuth2Client.generateAuthUrl({ @@ -63,10 +81,10 @@ async function getAccessToken(oAuth2Client) { const code = await ask('Enter the code from that page here: ') const token = (await oAuth2Client.getToken(code)).tokens oAuth2Client.setCredentials(token); - await promisify(fs.writeFile)(config.tokenPath, JSON.stringify(token)) - console.log('Token stored to', config.tokenPath); + await pass_insert('skl-auto-payslip', JSON.stringify(token)) return oAuth2Client } + class InvoiceDocument { constructor(auth, fileId) { Object.assign(this, { @@ -171,16 +189,20 @@ The total is ${total} to ${iban} (same as always). Thanks!` } const datefmt = date => `${date.getFullYear()}-${(""+(date.getMonth()+1)).padStart(2, '0')}-${(""+date.getDate()).padStart(2, '0')}` -const methods = { +class App { + constructor(auth) { + this.auth = auth + this.doc = new InvoiceDocument(auth, config.fileId) + } async export(sheetname, pdfOut) { // save sheet as pdf console.log("Exporting", sheetname, "to", pdfOut) const sheetId = await this.doc.sheetByName(sheetname) return this.doc.sheetAsPdf(pdfOut, sheetId) - }, + } async create(sheetname, template=config.template) { // copy sheet from template console.log("Creating", sheetname, "from", template) return this.doc.copyTo(template, sheetname) - }, + } async update(sheetname, startDate, endDate, hours) { // set values in sheet console.log("Setting data in", sheetname) hours = +hours @@ -194,7 +216,7 @@ const methods = { D16: values.regular, D17: values.overwork, B9: values.startDate, D9: values.endDate }) - }, + } async draft(sheetname) { // export pdf+create gmail draft const pdfname = `${config.destdir}/${sheetname}.pdf` try { @@ -207,7 +229,7 @@ const methods = { const iban = paid.replace(/^Paid to /, '') console.log(paid, total) composeDraft(sheetname, iban, total, pdfname, this.auth) - }, + } async auto(hours) { // just do everything const date = new Date() const day = date.getDate() @@ -244,31 +266,9 @@ const methods = { } await this.update(sheetname, startDate, endDate, hours) await this.draft(sheetname) - }, + } async authenticate() { // just auth } } - -const sig = fn => - fn.toString().split('\n')[0].replace(/^async /, '').replace(/ \{/, '') - -// poor man's CLI -const [,, method, ...args] = process.argv -if (method in methods) { - if (args.length < methods[method].length) { - console.error("not enough arguments for method", sig(methods[method])) - } else { - authAll().then((auth) => { - methods.auth = auth - methods.doc = new InvoiceDocument(auth, config.fileId) - methods[method](...args) - }) - } -} else { - if (method && method != 'help') console.log("unknown subcall", method) - console.log("valid methods:") - for(const realMethod in methods) { - console.log(" ", sig(methods[realMethod])) - } - process.exit(1) -} +module.exports = App +module.exports.authAll = authAll diff --git a/package.json b/package.json index 6f0bdf4..aefc5f5 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, + "bin": "bin/skl-auto-payslip.js", "author": "", "license": "ISC", "dependencies": {