UNPKG

teamwork-cli

Version:

Command-line-interface for the Teamwork (https://www.teamwork.com/time-tracking) time entry system.

413 lines (342 loc) 16.8 kB
/************************************************************************************ * Main script - parses arguments ************************************************************************************/ const versionNo = "1.1.17"; const dateFormat = require('dateformat'); const functions = require('./common-functions.js'); const userData = require('./user-data.js'); const teamwork = require('./teamwork.js'); /** * Parses the arguments provided to the program * * @param args Array of program arguments */ const parseProgramArguments = (args) => { // parse arguments let argList = {}; // creates an object for the arglist object const getArgEntry = (letter, argument, description, defaultValue) => { return {letter, argument, description, "provided": false, "value": defaultValue}; }; // help argList['help'] = getArgEntry('h', null, 'Print this help Screen', false); argList['version'] = getArgEntry('v', null, 'Print version info', false); // interactive argList['interactive'] = getArgEntry('i', '[path]', 'Enter interactive mode. Optionally add path to start in.', '.'); // lists of info argList['time-logged'] = getArgEntry('l', null, 'Print time logged', false); argList['tasks'] = getArgEntry('p', null, 'Print a list of previous entered tasks for the year', ''); argList['entries'] = getArgEntry('q', null, 'Print entries of today or date specified', dateFormat(new Date(), "yyyymmdd")); argList['since'] = getArgEntry('Q', null, 'Print entries since date specified', 'week'); argList['favorites'] = getArgEntry('f', null, 'Print the list of your favorites', false); argList['favorites-full'] = getArgEntry('F', null, 'Print the list of your favorites and their tasks', false); argList['timers'] = getArgEntry('P', null, 'Prints list of timers', false); argList['percentages'] = getArgEntry('w', null, 'Print percentages of time logged', 'week'); argList['get'] = getArgEntry('g', null, 'Print a peice of data', 'time-worked'); // time logging argList['interactive-entry'] = getArgEntry('E', '[taskId]', 'Enter time through questions for specified task', ''); argList['entry'] = getArgEntry('e', null, 'Enter time with below options', false); argList['billable'] = getArgEntry('b', '[0/1]', 'If billable time (default 1)', true); argList['hours'] = getArgEntry('H', '[hours]', 'Set hours to log (default 0)', 0); argList['minutes'] = getArgEntry('M', '[minutes]', 'Set minutes to log (default 0)', 0); argList['date'] = getArgEntry('d', '[yyyymmdd]', 'Set date to log for (default today)', dateFormat(new Date(), "yyyymmdd")); argList['description'] = getArgEntry('m', '[message]', 'Set description to log (default empty)', ''); argList['task'] = getArgEntry('t', '[taskId]', 'Set the taskId to log to (see --tasks)', ''); argList['start-time'] = getArgEntry('T', '[HH:MM]', 'Set the start time to log (default 09:00)', '09:00'); argList['end-time'] = getArgEntry('O', '[HH:MM]', 'Set the length based on the start/end time (default empty)', ''); argList['tags'] = getArgEntry('z', '[tag1,tag2,tag3]', 'Adds a tag to the time entry. Surround list with quotes if it includes a space', ''); argList['move'] = getArgEntry('c', '[EntryId]', 'Move the time entry to the task specified by --task', null); // persistence argList['key'] = getArgEntry('k', '[key]', 'Set teamwork API key to use in the future', ''); argList['url'] = getArgEntry('u', '[url]', 'Set teamwork URL to use in the future', ''); argList['arrived'] = getArgEntry('a', '[HH:MM]', 'Record the time as when you arrived (default to now)', new Date()); argList['switch'] = getArgEntry('s', '[timer]', 'Switch to a different timer', ''); argList['startstop'] = getArgEntry('S', '[timer]', 'Start or stop a timer', ''); argList['delete-timer'] = getArgEntry('D', '[timer]', 'Delete a timer', ''); argList['add-timer'] = getArgEntry('A', '[timer]', 'Along with -H and -M adds time to a timer', ''); argList['subtract-timer'] = getArgEntry('x', '[timer]', 'Along with -H and -M subtract from a timer', ''); if (args !== undefined) { Object.keys(argList).forEach(key => { const index = Math.max(args.indexOf(`-${argList[key].letter}`), args.indexOf(`--${key}`)); if (index > -1) { if (args.length > index) { argList[key].provided = true; if (args.length > index + 1 && !args[index + 1].startsWith('-')) { argList[key].value = args[index + 1]; } } } }); } return argList; }; /** * Prints Version of program */ const printVersionInfo = () => { console.log(`hours ${versionNo}\n`); }; /** * Print Usage for the utility */ const printUsage = (interactiveUsage) => { printVersionInfo(); const argList = parseProgramArguments(); console.log('OPTIONS'); Object.keys(argList).forEach(key => { const letter = argList[key].letter; const description = argList[key].description; const optArg = argList[key].argument == null ? "" : argList[key].argument; // Print option, key, description console.log('\n\t' + `-${letter}, --${key} ${optArg}` + '\n\t' + description) } ); console.log('\nEXAMPLES'); console.log(` node hours.js --entry --task 6905921 --start-time "09:00" --hours 1 --minutes 30 --billable 0 --description "Friday Standup" Logs an hour and a half for a long Friday standup node hours.js -e -t 6905921 -T "09:00" -H 1 -M 30 -b 0 -m "Friday Standup" Same as above but using letters instead ` ); console.log('\nINTERACTIVE MODE\n'); interactiveUsage(); }; const persistKey = (key) => { if (typeof key === 'string' && key.length > 0) { userData.get().teamwork.key = key; userData.save(); } }; const persistUrl = (url) => { if (typeof url === 'string' && url.length > 0) { userData.get().teamwork.url = url; userData.save(); } }; const persistStartTime = (time) => { const data = userData.get(); if (typeof time === 'string' && time !== 'now') { const overrides = time.split(':'); const date = new Date(); date.setHours(overrides[0]); date.setMinutes(overrides[1]); data.arrived = date; } else { data.arrived = time; } console.log('Marking that you arrived at ' + data.arrived); userData.save(); }; const getTimeDiff = (startTime, endTime) => { const startColon = startTime.indexOf(':'); const endColon = endTime.indexOf(':'); const startHour = Number(startTime.substring(0, startColon)); const startMinute = Number(startTime.substring(startColon + 1, 5)); const endHour = Number(endTime.substring(0, endColon)); const endMinute = Number(endTime.substring(endColon + 1, 5)); const value = { hours: endHour - startHour, minutes: endMinute - startMinute }; if (value.hours < 0) { value.hours += 12; } if (value.minutes < 0) { value.hours -= 1; value.minutes += 60; } return value; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // "Main" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const main = (args, interactiveCommands) => { try { const {interactiveMode, logTimeInteractive, usage} = interactiveCommands; const data = userData.get(); // if no arguments, just print time logged if (args.length < 3) { functions.printTimeLogged(); } else { const argList = parseProgramArguments(args); // do work if (argList['help'].provided) { printUsage(usage); } else { if (argList['key'].provided) { persistKey(argList['key'].value); } if (argList['url'].provided) { persistUrl(argList['url'].value); } if (argList['arrived'].provided) { persistStartTime(argList['arrived'].value); } if (argList['startstop'].provided) { const timers = userData.get().timers; const id = argList['startstop'].value; if (id && id.length > 0) { const timer = userData.get().timers[id]; if (timer) { if (timer.running) { functions.stopTimer(id); const length = functions.getDurationString(timer.duration); console.log(`Timer ${id} stopped at ${length}.`); } else { functions.startTimer(id); const {started} = userData.get().timers[id]; const length = functions.getDurationString(timer.duration); console.log(`Timer ${id} resumed from ${length} at ${started}.`); } } else { functions.startTimer(id); const {started} = userData.get().timers[id]; console.log(`Recorded start time for ${id} as ${started}.`); } } else { // stop all timers Object.keys(timers).forEach(t => { if (timers[t].running) { functions.stopTimer(t); const tlength = functions.getDurationString(timers[t].duration); console.log(`Timer ${t} stopped at ${tlength}.`); } }); } } if (argList['switch'].provided) { const timers = userData.get().timers; const id = argList['switch'].value; let wasRunning = false; // stop all timers Object.keys(timers) .filter(t => timers[t].running) .forEach(t => { functions.stopTimer(t); const tlength = functions.getDurationString(timers[t].duration); console.log(`Timer ${t} stopped at ${tlength}.`); if (t === id) { wasRunning = true; } }); if (!wasRunning && id && id.length > 0) { functions.startTimer(id); const {started, duration} = userData.get().timers[id]; if (duration > 0) { const tlength = functions.getDurationString(duration); console.log(`Timer ${id} resumed from ${tlength} at ${started}.`); } else { console.log(`Timer ${id} started at ${started}.`); } } } if (argList['delete-timer'].provided) { const timers = userData.get().timers; const id = argList['delete-timer'].value; if (id && timers[id]) { const tlength = functions.getDurationString(timers[id].duration); delete timers[id]; console.log(`Deleted timer ${id} at ${tlength}`); } else { console.log(`Unable to find timer ${id} to delete`); } } if (argList['add-timer'].provided) { const id = argList['add-timer'].value; const hours = Number(argList['hours'].value); const minutes = Number(argList['minutes'].value); const duration = functions.modifyTimer(id, hours, minutes); console.log(`${id}: ${functions.getDurationString(duration)}`) } if (argList['subtract-timer'].provided) { const id = argList['subtract-timer'].value; const hours = -Number(argList['hours'].value); const minutes = -Number(argList['minutes'].value); const duration = functions.modifyTimer(id, hours, minutes); console.log(`${id}: ${functions.getDurationString(duration)}`) } if (argList['interactive-entry'].provided) { const resp = logTimeInteractive(argList['interactive-entry'].value); console.log(resp); } else if (argList['entry'].provided) { let hours = 0, minutes = 0; if (argList['start-time'].provided && argList['end-time'].provided) { const diff = getTimeDiff(argList['start-time'].value, argList['end-time'].value); hours = diff.hours; minutes = diff.minutes; } if (argList['hours'].provided) { hours = argList['hours'].value; } if (argList['minutes'].provided) { minutes = argList['minutes'].value; } const resp = functions.sendTimeEntry({ taskId: argList['task'].value, description: argList['description'].value, date: argList['date'].value, hours: hours, minutes: minutes, isbillable: argList['billable'].value, time: argList['start-time'].value, tags: argList['tags'].value.split(','), }); console.log(resp); } else if (argList['tasks'].provided) { functions.printPreviousTasks(); } else if (argList['move'].provided && argList['task'].provided) { const entry = teamwork.getTimeEntry(argList['move'].value); functions.moveTimeEntry(entry, argList['task'].value); } if (argList['time-logged'].provided) { functions.printTimeLogged(); } if (argList['percentages'].provided) { functions.printPercentages(argList['percentages'].value); } if (argList['get'].provided) { functions.printItem(argList['get'].value); // escape for saving data return; } if (argList['version'].provided) { printVersionInfo(); } if (argList['entries'].provided) { functions.printDateEntries(argList['entries'].value); } if (argList['since'].provided) { const dateStr = functions.getSinceDate(argList['since'].value); const date = functions.parseDateYYYYMMDD(dateStr); const today = new Date(); while (date < today) { console.log('\n\nDate: ' + date); functions.printDateEntries(dateFormat(date, "yyyymmdd")); date.setDate(date.getDate() + 1); } } if (argList['favorites'].provided) { functions.listFavorites(); } if (argList['favorites-full'].provided) { functions.listFavorites(true); } if (argList['timers'].provided) { functions.listTimers(); } if (argList['interactive'].provided && interactiveMode) { interactiveMode(argList['interactive'].value); } } } userData.save(data); } catch (e) { console.log(e); } }; module.exports = main;