1+ # Licensed under the Apache License, Version 2.0 (the "License");
2+ # you may not use this file except in compliance with the License.
3+ # You may obtain a copy of the License at
4+
5+ # http://www.apache.org/licenses/LICENSE-2.0
6+
7+ # Unless required by applicable law or agreed to in writing, software
8+ # distributed under the License is distributed on an "AS IS" BASIS,
9+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+ # See the License for the specific language governing permissions and
11+ # limitations under the License.
12+
13+
14+ from __future__ import unicode_literals
15+
16+ import itertools
17+ import requests
18+ import six
19+
20+ from calendar import monthrange
21+ from datetime import date , datetime
22+ from django .utils .dateparse import parse_datetime , parse_date
23+ from six .moves .urllib .parse import quote
24+
25+
26+ class Tempo (object ):
27+ # Maximum number of result in single response (pagination)
28+ # NOTE: maximum number allowed by API is 1000
29+ MAX_RESULTS = 1000
30+
31+ def __init__ (self , base_url , auth_token ):
32+ self ._token = auth_token
33+ self .BASE_URL = base_url
34+
35+ def _resolve_date (self , value ):
36+ if isinstance (value , datetime ):
37+ return value .date ()
38+ if isinstance (value , date ):
39+ return value
40+ parsed = parse_date (value )
41+ if not parsed :
42+ parsed = parse_datetime (value )
43+ if not parsed :
44+ raise ValueError ()
45+ return parsed .date ()
46+ return parsed
47+
48+ def _list (self , url , ** params ):
49+ # Resolve parameters
50+ url = self .BASE_URL + url
51+ headers = { "Authorization" : "Bearer {}" .format (self ._token ) }
52+ params = params .copy ()
53+
54+ # Return paginated results
55+ processed = 0
56+ while True :
57+ params ["offset" ] = processed
58+ response = requests .get (url , params = params , headers = headers )
59+ response .raise_for_status ()
60+ data = response .json ()
61+ metadata = data .get ("metadata" , {})
62+ results = data .get ("results" , [])
63+ processed += metadata .get ("count" , 0 )
64+ for result in results :
65+ yield result
66+ if "next" not in metadata or metadata .get ("count" , 0 ) < metadata .get ("limit" , 0 ):
67+ break
68+
69+ def _get_work_attributes (self ):
70+ return { x ["key" ]: x for x in self ._list ("/work-attributes" ) }
71+
72+ def _iterate_worklogs (self , date_from , date_to , user = None ):
73+ work_attributes = None
74+ date_from = self ._resolve_date (date_from ).isoformat ()
75+ date_to = self ._resolve_date (date_to ).isoformat ()
76+ url = "/worklogs"
77+ if user is not None :
78+ url += "/user/{}" .format (user )
79+ params = { "from" : date_from , "to" : date_to , "limit" : self .MAX_RESULTS }
80+ for worklog in self ._list (url , ** params ):
81+ attributes = (worklog .get ("attributes" ) or {}).get ("values" ) or []
82+ resolved_attributes = {}
83+ if attributes :
84+ if work_attributes is None :
85+ work_attributes = self ._get_work_attributes ()
86+ for attribute in attributes :
87+ key = attribute ["key" ]
88+ name = work_attributes .get (key , {}).get ("name" , key )
89+ resolved_attributes [name ] = attribute ["value" ]
90+ worklog ["attributes" ] = resolved_attributes
91+ yield worklog
92+
93+ def get_worklogs (self , date_from , date_to , user = None ):
94+ return list (self ._iterate_worklogs (date_from , date_to , user ))
95+
96+ def _iterate_user_schedule (self , date_from , date_to , user ):
97+ date_from = self ._resolve_date (date_from ).isoformat ()
98+ date_to = self ._resolve_date (date_to ).isoformat ()
99+ url = "/user-schedule"
100+ if user is not None :
101+ url += "/{}" .format (user )
102+ params = { "from" : date_from , "to" : date_to , "limit" : self .MAX_RESULTS }
103+ return self ._list (url , ** params )
104+
105+ def get_user_schedule (self , date_from , date_to , user ):
106+ return list (self .iterate_schedule (date_from , date_to , user ))
0 commit comments