forked from wycomco/kimai-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkimai.py
167 lines (121 loc) · 4.37 KB
/
kimai.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
156
157
158
159
160
161
162
163
164
165
166
167
import requests
import json
import config
import dates
from datetime import datetime
def _build_payload(method, *args):
quoted_args = ['\"%s\"' % arg for arg in args]
return '{"jsonrpc":"2.0", "method":"%s", "params":[%s], "id":"1"}' \
% (method, ','.join(quoted_args))
def _build_record_payload(method, record, update=False):
# Make it compatible with PHP's json decode
update = 'true' if update else 'false'
return '{"jsonrpc":"2.0", "method":"%s", "params":["%s", %s, %s], "id":"1"}' \
% (method, config.get('ApiKey'), json.dumps(record), update)
def _do_request(payload):
kimai_url = config.get('KimaiUrl')
return requests.post('{}/core/json.php'.format(kimai_url), data=payload)
def authenticate(username, password):
"""Authenticate a user against the kimai backend."""
payload = _build_payload('authenticate', username, password)
response = _do_request(payload)
return KimaiAuthResponse(response)
def get_projects():
"""Return a list of all available projects."""
payload = _build_payload('getProjects', config.get('ApiKey'))
response = KimaiResponse(_do_request(payload))
return response.items
def get_tasks():
"""Return a list of all available tasks."""
payload = _build_payload('getTasks', config.get('ApiKey'))
response = KimaiResponse(_do_request(payload))
return response.items
def start_recording(task_id, project_id):
"""Starts a new recording for the provided task and project."""
payload = _build_payload(
'startRecord',
config.get('ApiKey'),
project_id,
task_id
)
return KimaiResponse(_do_request(payload))
def stop_recording():
"""Stops the running record if there is one."""
current_record = get_current()
if current_record is None:
return
payload = _build_payload(
'stopRecord',
config.get('ApiKey'),
current_record['timeEntryID']
)
return KimaiResponse(_do_request(payload))
def get_current():
"""Returns the currently running record if there is any."""
timesheet = get_timesheet()
if not timesheet:
return
if timesheet[0]['end'] != '0':
return
return Record(timesheet[0])
def get_todays_records():
"""Returns all records for the current day"""
payload = _build_payload(
'getTimesheet',
config.get('ApiKey'),
dates.parse('today at 00:00').isoformat(),
dates.parse('today at 23:59:59').isoformat()
)
response = KimaiResponse(_do_request(payload))
return [Record(r) for r in response.items]
def get_timesheet():
payload = _build_payload('getTimesheet', config.get('ApiKey'))
response = KimaiResponse(_do_request(payload))
return response.items
def add_record(start, end, project, task, comment=''):
payload = _build_record_payload('setTimesheetRecord', {
'start': start.isoformat(),
'end': end.isoformat(),
'projectId': project,
'taskId': task,
'statusId': 1,
'comment': comment
})
return KimaiResponse(_do_request(payload))
# TODO: Holy shit this doesn't check that I'm actually deleting one of my
# own records...
def delete_record(id):
payload = _build_payload('removeTimesheetRecord', config.get('ApiKey'), id)
return KimaiResponse(_do_request(payload))
class KimaiResponse(object):
"""Generic response object for the Kimai (sort of) JSON API"""
def __init__(self, response):
self.data = json.loads(response.text)['result']
@property
def successful(self):
return self.data['success']
@property
def error(self):
if self.successful:
return None
return self.data['error']['msg']
@property
def items(self):
if not self.successful:
return None
return self.data['items']
class KimaiAuthResponse(KimaiResponse):
"""Specific response for the result of an authentication request"""
@property
def apiKey(self):
if not self.successful:
return None
return self.items[0]['apiKey']
class Record(dict):
def __getitem__(self, key):
if key in ['start', 'end']:
value = int(super(Record, self).__getitem__(key))
if value == 0:
return '-'
return datetime.fromtimestamp(value).strftime('%H:%M:%S')
return super(Record, self).__getitem__(key)