Skip to content

Instantly share code, notes, and snippets.

@alex-streza
Created December 23, 2023 15:38
Show Gist options
  • Save alex-streza/5ddbf80c38637b374349db6a7ef7c85b to your computer and use it in GitHub Desktop.
Save alex-streza/5ddbf80c38637b374349db6a7ef7c85b to your computer and use it in GitHub Desktop.
Node.js script to fetch Toggl time entries via the official API, organizing data into a monthly CSV timesheet.
const fetch = require('node-fetch');
const jsonexport = require('jsonexport');
const fs = require('fs').promises;
const path = require('path');
const API_URL = process.env.API_URL;
const EMAIL = process.env.EMAIL;
const PASSWORD = process.env.PASSWORD;
const OUTPUT_PATH = process.env.OUTPUT_PATH;
const NAME = process.env.NAME;
const config = {
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${Buffer.from(`${EMAIL}:${PASSWORD}`).toString('base64')}`,
},
};
const months = [
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december",
];
const getStartEndMonthDates = () => {
const today = new Date();
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
return [firstDay, lastDay];
};
const getHoursBetweenDates = (start, end) => {
const diff = end.getTime() - start.getTime();
return diff / (1000 * 60 * 60);
};
const fetchData = async (url) => {
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
throw new Error(error.message);
}
};
const writeToFile = async (filePath, data) => {
try {
await fs.writeFile(filePath, data);
console.log(`File saved at: ${filePath}`);
} catch (error) {
throw new Error(error.message);
}
};
(async () => {
try {
const [start] = getStartEndMonthDates();
const currentMonth = months[start.getMonth()];
const projectsResponse = await fetchData(`${API_URL}/projects`);
const projects = projectsResponse.data;
const entriesResponse = await fetchData(`${API_URL}/time_entries?since=${Math.floor(start.getTime() / 1000)}`);
const entries = [];
for (const entry of entriesResponse) {
const { start, stop, description, pid } = entry;
const project = projects.find((project) => project.id === pid);
entries.push({
date: start.split("T")[0].split("-").reverse().join("/"),
project: project ? project.name : "Unknown",
person: NAME,
task: description,
hours: getHoursBetweenDates(new Date(start), new Date(stop)),
});
}
jsonexport(entries, async (err, csv) => {
if (err) return console.error(err);
const filePath = path.join(OUTPUT_PATH, `${currentMonth}.csv`);
await writeToFile(filePath, csv);
});
} catch (e) {
console.error(e);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment