-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtoggl.py
155 lines (141 loc) · 6.21 KB
/
toggl.py
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
from core import Core
import requests
import json
class Toggl(Core):
"""Contains all Toggl related operations."""
def __init__(self):
super(Toggl, self).__init__()
self.BOOKED_TAG = "\U0001F343" # tag used for flagging Toggl projects
self.clients = None # will contain loaded Toggl clients
self.projects = None # will contain loaded Toggl projects
def get_clients(self):
"""Returns dictionary of all Toggl clients with key/value name/id."""
if self.clients:
return self.clients
else:
return self.load_clients()
def load_clients(self):
"""Loads Toggl clients from their API and saves them to object."""
self.print("Loading Toggl clients...")
url = 'https://www.toggl.com/api/v8/clients'
response = requests.get(url, auth=self.toggl_creds).json()
clients = {}
for result in response:
clients[result['name']] = result['id']
self.clients = clients # store for later use
return clients
def get_client_id(self, name=None, project_id=None):
"""Returns client id based on either name or project id.
Uses fuzzy matching for matching names."""
if project_id:
url = 'https://www.toggl.com/api/v8/projects/' + str(project_id)
response = requests.get(url, auth=self.toggl_creds)
return response.json()['data'].get('cid')
elif name:
if self.get_clients().get(name):
return self.get_clients()[name]
else:
# Fuzzy string matching ahead, beware!
choices = self.get_clients().keys()
best_match = self.fuzzy_match(name, choices, cutoff=90)
if best_match:
self.log("Fuzzy matched '%s' to Toggl project '%s'." % (name, best_match))
return self.get_clients()[best_match]
else:
self.log("Couldn't accurately find a client with that name.")
return None
def get_client_name(self, client_id):
"""Returns name of Toggl client, accepts Toggl client id."""
for name, _id in self.get_clients().items():
if client_id == _id:
return name
return None
def create_client(self, name, workspace_id=None):
"""Creates a new Toggl client. Returns Toggl's JSON response.
If no workspace id is specified, the id for the first workspace will be assumed."""
if not workspace_id:
workspaces = self.get_workspaces()
workspace_id = workspaces[0]['id']
self.print("No workspace ID specified, assuming workspace id %s" % str(workspace_id), 'warn')
headers = {
'Content-Type': 'application/json',
}
data = {
"client": {
"name": name,
"wid": workspace_id
}
}
data = json.dumps(data)
url = 'https://www.toggl.com/api/v8/clients'
response = requests.post(url, headers=headers, data=data, auth=self.toggl_creds)
client = response.json()['data']
self.load_clients()
return client
def get_project(self, project_id):
"""Returns Toggl project in json format. Accepts project id."""
url = 'https://www.toggl.com/api/v8/projects/' + str(project_id)
response = requests.get(url, auth=self.toggl_creds)
return response.json()['data']
def create_project(self, title, client_id=None, is_private=True):
"""Creates Toggl project with specified title and (optional) client id.
Returns API response in json (if possible)."""
headers = {
'Content-Type': 'application/json',
}
data = {
"project": {
"name": title,
"cid": client_id if client_id else False,
"is_private": is_private
}
}
data = json.dumps(data)
url = 'https://www.toggl.com/api/v8/projects'
response = requests.post(url, headers=headers, data=data, auth=self.toggl_creds)
try:
return response.json()
except:
return response.text
def tag_projects(self, id_list, tag=None):
"""Tags Toggl time entries. Accepts list of toggl time entry IDs and tag."""
if not tag:
tag = self.BOOKED_TAG
headers = {
'Content-Type': 'application/json',
}
data = {
"time_entry": {
"tags": [tag]
}
}
data = json.dumps(data)
url = 'https://www.toggl.com/api/v8/time_entries/' + ','.join(str(i) for i in id_list)
response = requests.post(url, headers=headers, data=data, auth=self.toggl_creds)
self.print('Tagged Toggl %s. ' % ('entry' if len(id_list) == 1 else 'entries') + self.BOOKED_TAG, 'ok')
return response.json()
def get_projects(self):
"""Retrieves and returns all projects visible to current user as array of JSON objects."""
if self.projects:
return self.projects
self.print("Loading Toggl projects...")
params = {'with_related_data': 'true'}
url = 'https://www.toggl.com/api/v8/me'
response = requests.get(url, params=params, auth=self.toggl_creds)
projects = response.json()['data']['projects']
self.projects = projects # save for later
return projects
def get_time_entries(self, timestamp):
"""Returns all Toggl time entries from specified starting point as json array.
Timestamp should be in isoformat including timezone info."""
self.print("Loading Toggl time entries...")
params = {'start_date': timestamp}
response = requests.get('https://www.toggl.com/api/v8/time_entries', params=params, auth=self.toggl_creds)
time_entries = response.json()
return time_entries
def get_workspaces(self):
"""Fetches all Toggl workspaces. Returns list of (json) workspaces."""
url = 'https://www.toggl.com/api/v8/workspaces'
response = requests.get(url, auth=self.toggl_creds)
workspaces = response.json()
return workspaces