Automation 101 - simple time tracking web service

Time tracking is awful. We know that. So why not automate it?

Therefore, I built a simple time tracking web service to easily start and stopp Toggl time entries (which can be basically projects or subtasks, whatever you like). This web service can then be used by various apps and services which can interact with HTTP calls. I just tried it with MacroDroid to enable location-based time tracking and it worked like a charm.

So what do we need?

  • an Toggl account (it’s free)
  • a cheap, secure and highly available cloud platform (in my case Google Cloud Platform, see below) to host our little service, so that we don’t need to mess around with Firewall rules, NAT, port exposure, hardening, VLANs, WAF, you name it…
  • the service itself (a few lines of code)

The service is built using the Python framework Flask, which enables you to easily build both simple and powerful web applications. It uses HTTP endpoints (some call it REST API) to do something on request, in our case start or stop time entries. To secure that thing, some sort of authentication mechanism is strongly advised. It will be deployed in Google App Engine using the free tier.

To download the whole code, click here.

Beware: at the time of this writing, everything worked fine. Since packages, frameworks, endpoints, etc. change over time, you might need to adapt the code to address current requirements and conditions.

My service has the following folder structure:

.
├── app.yaml
├── favicon.ico
├── main.py
├── requirements.txt
├── tasks
│   └── run.py
└── templates
    ├── error.html
    └── index.html

and uses the following HTTP endpoints:

  • https://<URL>/start for starting time tracking
  • https://<URL>/stop for stopping time tracking


Pre-Requirements

Go to your Toggl Profile Settings and copy your API token.

Use the following commands to get your Toggl workspace and project ID. Replace <API-TOKEN> with your API token and <WORKSPACE-ID> with your workspace ID.

# get workspace IDs
curl -su <API-TOKEN>:api_token \
  -X GET https://www.toggl.com/api/v8/workspaces | jq '.[0].id'

# get project IDs in given workspace
curl -su <API-TOKEN>:api_token \
  -X GET https://www.toggl.com/api/v8/dashboard/<WORKSPACE-ID> \
  | jq '.activity[0].project_id'

If you’re unfamiliar with jq, just use the native curl command without piping jq and manually search for the information.

Prepare your App Engine environment using this guide. You don’t need to deploy the Hello World App from Google, just make sure the gcloud command line tool is installed and configured.


Setup Flask app

Have a look at main.py:

Edit the user credentials, which are used for simple Basic Auth to successfully access your HTTP endpoints:

users = {
    "john": generate_password_hash("SuperSecurePassword")
}
Have a look at tasks/run.py:

Edit the Toggl API token:

# add your Toggl API Token
API_TOKEN = "123456789"

Edit your workspace (wid) and project (pid) ID accordingly:

#-- edit your workspace and project IDs
payload = {"time_entry":{"wid":123456789,"pid":123456789,"created_with":"curl"}}
#--

Deploy the Flask app in Google App Engine with gcloud app deploy:

$ gcloud app deploy
Services to deploy:

descriptor:      [/path/to/app.yaml]
source:          [/path]
target project:  [project-123456]
target service:  [default]
target version:  [2022121t123456]
target url:      [https://project-123456.ey.r.appspot.com]


Do you want to continue (Y/n)?  y

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.                                                                                                                                                                                  
Setting traffic split for service [default]...done.                                                                                                                                                                 
Deployed service [default] to [https://project-123456.ey.r.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse


Test the web service

Access https://<URL>/start and https://<URL>/stop (you find the URLs in the app-deploy output) using your browser or any other HTTP client. You should get some JSON data as response.

In Toggl, the desired time entry should get started:

toggl

You should also see some logs in the Log Console. Make sure you select the time-tracker-log in the Global resources.

You maybe wonder: but I have never authenticated against GCP in my Python app? Yes, that’s part of the “magic” of the App Engine. As soon as you’re inside the environment, you don’t need to authenticate anymore. Can be good or bad, tbh…

That’s it! You now have a small web service that controls the Toggl time tracker and logs everything in the cloud.