summaryrefslogtreecommitdiff
path: root/overlays
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2023-01-05 23:43:48 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2023-01-05 23:43:48 +0100
commitd583b7d1144e14861b29a07393983bae10315933 (patch)
tree9de0686dc4c0baf7534c6cbf884f1047bd588cb9 /overlays
parent674c7ae9b02296819aaec5c1cd8e79579e455eea (diff)
downloadnixos-d583b7d1144e14861b29a07393983bae10315933.tar
nixos-d583b7d1144e14861b29a07393983bae10315933.tar.gz
nixos-d583b7d1144e14861b29a07393983bae10315933.tar.bz2
nixos-d583b7d1144e14861b29a07393983bae10315933.tar.xz
nixos-d583b7d1144e14861b29a07393983bae10315933.zip
worktime: multi-client support
Diffstat (limited to 'overlays')
-rwxr-xr-xoverlays/worktime/worktime.py57
1 files changed, 50 insertions, 7 deletions
diff --git a/overlays/worktime/worktime.py b/overlays/worktime/worktime.py
index 310fa084..166bea1c 100755
--- a/overlays/worktime/worktime.py
+++ b/overlays/worktime/worktime.py
@@ -46,9 +46,10 @@ class TogglAPIError(Exception):
46 return self.response.text 46 return self.response.text
47 47
48class TogglAPI(object): 48class TogglAPI(object):
49 def __init__(self, api_token, workspace_id): 49 def __init__(self, api_token, workspace_id, client_ids):
50 self._api_token = api_token 50 self._api_token = api_token
51 self._workspace_id = workspace_id 51 self._workspace_id = workspace_id
52 self._client_ids = set(map(int, client_ids.split(','))) if client_ids else None
52 53
53 def _make_url(self, api=TogglAPISection.TOGGL, section=['time_entries', 'current'], params={}): 54 def _make_url(self, api=TogglAPISection.TOGGL, section=['time_entries', 'current'], params={}):
54 if api is TogglAPISection.REPORTS: 55 if api is TogglAPISection.REPORTS:
@@ -87,11 +88,35 @@ class TogglAPI(object):
87 elif req_start > start_date: 88 elif req_start > start_date:
88 req_start = datetime.combine(req_start.astimezone(timezone.utc).date(), time(tzinfo=timezone.utc)) + timedelta(days = 1) 89 req_start = datetime.combine(req_start.astimezone(timezone.utc).date(), time(tzinfo=timezone.utc)) + timedelta(days = 1)
89 90
90 url = self._make_url(api = TogglAPISection.REPORTS, section = ['summary'], params={'since': req_start.astimezone(timezone.utc).isoformat(), 'until': req_end.astimezone(timezone.utc).isoformat(), 'rounding': rounding}) 91 def get_report(client_ids = self._client_ids):
91 r = self._query(url = url, method='GET') 92 nonlocal req_start, req_end, rounding, self
92 if not r or not r.json(): 93
93 raise TogglAPIError(r) 94 if client_ids is not None and not client_ids:
94 billable_acc += timedelta(milliseconds=r.json()['total_billable']) if r.json()['total_billable'] else timedelta(milliseconds=0) 95 return timedelta(milliseconds = 0)
96
97 params = { 'since': req_start.astimezone(timezone.utc).isoformat(),
98 'until': req_end.astimezone(timezone.utc).isoformat(),
99 'rounding': rounding,
100 'billable': 'yes'
101 }
102 if client_ids is not None:
103 params |= { 'client_ids': ','.join(map(str, client_ids)) }
104 url = self._make_url(api = TogglAPISection.REPORTS, section = ['summary'], params = params)
105 r = self._query(url = url, method='GET')
106 if not r or not r.json():
107 raise TogglAPIError(r)
108 res = timedelta(milliseconds=r.json()['total_billable']) if r.json()['total_billable'] else timedelta(milliseconds=0)
109 return res
110
111 if 0 in self._client_ids:
112 url = self._make_url(api = TogglAPISection.TOGGL, section = ['workspaces', self._workspace_id, 'clients'])
113 r = self._query(url = url, method = 'GET')
114 if not r or not r.json():
115 raise TogglAPIError(r)
116
117 billable_acc += get_report(None) - get_report(set(map(lambda c: c['id'], r.json())))
118
119 billable_acc += get_report(self._client_ids - {0})
95 120
96 return billable_acc 121 return billable_acc
97 122
@@ -105,6 +130,24 @@ class TogglAPI(object):
105 if not r.json()['data'] or not r.json()['data']['billable']: 130 if not r.json()['data'] or not r.json()['data']['billable']:
106 return None 131 return None
107 132
133 if self._client_ids is not None:
134 if 'pid' in r.json()['data'] and r.json()['data']['pid']:
135 url = self._make_url(api = TogglAPISection.TOGGL, section = ['projects', str(r.json()['data']['pid'])])
136 pr = self._query(url = url, method = 'GET')
137 if not pr or not pr.json():
138 raise TogglAPIError(pr)
139
140 if not pr.json()['data']:
141 return None
142
143 if 'cid' in pr.json()['data'] and pr.json()['data']['cid']:
144 if pr.json()['data']['cid'] not in self._client_ids:
145 return None
146 elif 0 not in self._client_ids:
147 return None
148 elif 0 not in self._client_ids:
149 return None
150
108 start = isoparse(r.json()['data']['start']) 151 start = isoparse(r.json()['data']['start'])
109 152
110 return now - start if start <= now else None 153 return now - start if start <= now else None
@@ -170,7 +213,7 @@ class Worktime(object):
170 213
171 config = Worktime.config() 214 config = Worktime.config()
172 config_dir = BaseDirectory.load_first_config('worktime') 215 config_dir = BaseDirectory.load_first_config('worktime')
173 api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace']) 216 api = TogglAPI(api_token=config['TOGGL']['ApiToken'], workspace_id=config['TOGGL']['Workspace'], client_ids=config.get('TOGGL', 'ClientIds', fallback=None))
174 date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d') 217 date_format = config.get('WORKTIME', 'DateFormat', fallback='%Y-%m-%d')
175 218
176 start_date = start_datetime or datetime.strptime(config['WORKTIME']['StartDate'], date_format).replace(tzinfo=tzlocal()) 219 start_date = start_datetime or datetime.strptime(config['WORKTIME']['StartDate'], date_format).replace(tzinfo=tzlocal())