55from azure .cosmos import PartitionKey
66from flask_restplus ._http import HTTPStatus
77
8- from commons .data_access_layer .cosmos_db import CosmosDBDao , CosmosDBRepository , CustomError , current_datetime_str , \
9- CosmosDBModel , get_date_range_of_month , get_current_year , get_current_month
8+ from commons .data_access_layer .cosmos_db import (
9+ CosmosDBDao ,
10+ CosmosDBRepository ,
11+ CustomError ,
12+ current_datetime_str ,
13+ CosmosDBModel ,
14+ get_date_range_of_month ,
15+ get_current_year ,
16+ get_current_month ,
17+ )
1018from commons .data_access_layer .database import EventContext
1119from time_tracker_api .database import CRUDDao , APICosmosDBDao
1220from time_tracker_api .security import current_user_id
@@ -34,10 +42,8 @@ def restart(self, id: str):
3442 'id' : 'time_entry' ,
3543 'partition_key' : PartitionKey (path = '/tenant_id' ),
3644 'unique_key_policy' : {
37- 'uniqueKeys' : [
38- {'paths' : ['/owner_id' , '/end_date' , '/deleted' ]},
39- ]
40- }
45+ 'uniqueKeys' : [{'paths' : ['/owner_id' , '/end_date' , '/deleted' ]}]
46+ },
4147}
4248
4349
@@ -66,15 +72,20 @@ def __repr__(self):
6672 return '<Time Entry %r>' % self .start_date # pragma: no cover
6773
6874 def __str___ (self ):
69- return "Time Entry started in \" %s\" " % self .start_date # pragma: no cover
75+ return (
76+ "Time Entry started in \" %s\" " % self .start_date
77+ ) # pragma: no cover
7078
7179
7280class TimeEntryCosmosDBRepository (CosmosDBRepository ):
7381 def __init__ (self ):
74- CosmosDBRepository .__init__ (self , container_id = container_definition ['id' ],
75- partition_key_attribute = 'tenant_id' ,
76- order_fields = ['start_date DESC' ],
77- mapper = TimeEntryCosmosDBModel )
82+ CosmosDBRepository .__init__ (
83+ self ,
84+ container_id = container_definition ['id' ],
85+ partition_key_attribute = 'tenant_id' ,
86+ order_fields = ['start_date DESC' ],
87+ mapper = TimeEntryCosmosDBModel ,
88+ )
7889
7990 @staticmethod
8091 def create_sql_ignore_id_condition (id : str ):
@@ -93,7 +104,9 @@ def create_sql_date_range_filter(date_range: dict) -> str:
93104 else :
94105 return ''
95106
96- def find_all (self , event_context : EventContext , conditions : dict , date_range : dict ):
107+ def find_all (
108+ self , event_context : EventContext , conditions : dict , date_range : dict
109+ ):
97110 custom_sql_conditions = []
98111 custom_sql_conditions .append (
99112 self .create_sql_date_range_filter (date_range )
@@ -106,9 +119,9 @@ def find_all(self, event_context: EventContext, conditions: dict, date_range: di
106119 event_context = event_context ,
107120 conditions = conditions ,
108121 custom_sql_conditions = custom_sql_conditions ,
109- custom_params = custom_params
122+ custom_params = custom_params ,
110123 )
111-
124+
112125 def on_create (self , new_item_data : dict , event_context : EventContext ):
113126 CosmosDBRepository .on_create (self , new_item_data , event_context )
114127
@@ -122,8 +135,16 @@ def on_update(self, updated_item_data: dict, event_context: EventContext):
122135 self .validate_data (updated_item_data , event_context )
123136 self .replace_empty_value_per_none (updated_item_data )
124137
125- def find_interception_with_date_range (self , start_date , end_date , owner_id , tenant_id ,
126- ignore_id = None , visible_only = True , mapper : Callable = None ):
138+ def find_interception_with_date_range (
139+ self ,
140+ start_date ,
141+ end_date ,
142+ owner_id ,
143+ tenant_id ,
144+ ignore_id = None ,
145+ visible_only = True ,
146+ mapper : Callable = None ,
147+ ):
127148 conditions = {
128149 "owner_id" : owner_id ,
129150 "tenant_id" : tenant_id ,
@@ -136,37 +157,54 @@ def find_interception_with_date_range(self, start_date, end_date, owner_id, tena
136157 params .extend (self .generate_params (conditions ))
137158 result = self .container .query_items (
138159 query = """
139- SELECT * FROM c WHERE ((c.start_date BETWEEN @start_date AND @end_date)
140- OR (c.end_date BETWEEN @start_date AND @end_date))
141- {conditions_clause} {ignore_id_condition} {visibility_condition} {order_clause}
142- """ .format (ignore_id_condition = self .create_sql_ignore_id_condition (ignore_id ),
143- visibility_condition = self .create_sql_condition_for_visibility (visible_only ),
144- conditions_clause = self .create_sql_where_conditions (conditions ),
145- order_clause = self .create_sql_order_clause ()),
160+ SELECT * FROM c
161+ WHERE ((c.start_date BETWEEN @start_date AND @end_date)
162+ OR (c.end_date BETWEEN @start_date AND @end_date))
163+ {conditions_clause}
164+ {ignore_id_condition}
165+ {visibility_condition}
166+ {order_clause}
167+ """ .format (
168+ ignore_id_condition = self .create_sql_ignore_id_condition (
169+ ignore_id
170+ ),
171+ visibility_condition = self .create_sql_condition_for_visibility (
172+ visible_only
173+ ),
174+ conditions_clause = self .create_sql_where_conditions (conditions ),
175+ order_clause = self .create_sql_order_clause (),
176+ ),
146177 parameters = params ,
147- partition_key = tenant_id )
178+ partition_key = tenant_id ,
179+ )
148180
149181 function_mapper = self .get_mapper_or_dict (mapper )
150182 return list (map (function_mapper , result ))
151183
152- def find_running (self , tenant_id : str , owner_id : str , mapper : Callable = None ):
184+ def find_running (
185+ self , tenant_id : str , owner_id : str , mapper : Callable = None
186+ ):
153187 conditions = {
154188 "owner_id" : owner_id ,
155189 "tenant_id" : tenant_id ,
156190 }
157191 result = self .container .query_items (
158192 query = """
159- SELECT * from c
160- WHERE (NOT IS_DEFINED(c.end_date) OR c.end_date = null)
161- {conditions_clause} {visibility_condition}
162- OFFSET 0 LIMIT 1
193+ SELECT * from c
194+ WHERE (NOT IS_DEFINED(c.end_date) OR c.end_date = null)
195+ {conditions_clause}
196+ {visibility_condition}
197+ OFFSET 0 LIMIT 1
163198 """ .format (
164- visibility_condition = self .create_sql_condition_for_visibility (True ),
199+ visibility_condition = self .create_sql_condition_for_visibility (
200+ True
201+ ),
165202 conditions_clause = self .create_sql_where_conditions (conditions ),
166203 ),
167204 parameters = self .generate_params (conditions ),
168205 partition_key = tenant_id ,
169- max_item_count = 1 )
206+ max_item_count = 1 ,
207+ )
170208
171209 function_mapper = self .get_mapper_or_dict (mapper )
172210 return function_mapper (next (result ))
@@ -176,20 +214,28 @@ def validate_data(self, data, event_context: EventContext):
176214
177215 if data .get ('end_date' ) is not None :
178216 if data ['end_date' ] <= start_date :
179- raise CustomError (HTTPStatus .BAD_REQUEST ,
180- description = "You must end the time entry after it started" )
217+ raise CustomError (
218+ HTTPStatus .BAD_REQUEST ,
219+ description = "You must end the time entry after it started" ,
220+ )
181221 if data ['end_date' ] >= current_datetime_str ():
182- raise CustomError (HTTPStatus .BAD_REQUEST ,
183- description = "You cannot end a time entry in the future" )
184-
185- collision = self .find_interception_with_date_range (start_date = start_date ,
186- end_date = data .get ('end_date' ),
187- owner_id = event_context .user_id ,
188- tenant_id = event_context .tenant_id ,
189- ignore_id = data .get ('id' ))
222+ raise CustomError (
223+ HTTPStatus .BAD_REQUEST ,
224+ description = "You cannot end a time entry in the future" ,
225+ )
226+
227+ collision = self .find_interception_with_date_range (
228+ start_date = start_date ,
229+ end_date = data .get ('end_date' ),
230+ owner_id = event_context .user_id ,
231+ tenant_id = event_context .tenant_id ,
232+ ignore_id = data .get ('id' ),
233+ )
190234 if len (collision ) > 0 :
191- raise CustomError (HTTPStatus .UNPROCESSABLE_ENTITY ,
192- description = "There is another time entry in that date range" )
235+ raise CustomError (
236+ HTTPStatus .UNPROCESSABLE_ENTITY ,
237+ description = "There is another time entry in that date range" ,
238+ )
193239
194240
195241class TimeEntriesCosmosDBDao (APICosmosDBDao , TimeEntriesDao ):
@@ -198,66 +244,93 @@ def __init__(self, repository):
198244
199245 @classmethod
200246 def check_whether_current_user_owns_item (cls , data : dict ):
201- if data .get ('owner_id' ) is not None \
202- and data .get ('owner_id' ) != cls .current_user_id ():
203- raise CustomError (HTTPStatus .FORBIDDEN ,
204- "The current user is not the owner of this time entry" )
247+ if (
248+ data .get ('owner_id' ) is not None
249+ and data .get ('owner_id' ) != cls .current_user_id ()
250+ ):
251+ raise CustomError (
252+ HTTPStatus .FORBIDDEN ,
253+ "The current user is not the owner of this time entry" ,
254+ )
205255
206256 @classmethod
207257 def checks_owner_and_is_not_stopped (cls , data : dict ):
208258 cls .check_whether_current_user_owns_item (data )
209259
210260 if data .get ('end_date' ) is not None :
211- raise CustomError (HTTPStatus .UNPROCESSABLE_ENTITY , "The specified time entry is already stopped" )
261+ raise CustomError (
262+ HTTPStatus .UNPROCESSABLE_ENTITY ,
263+ "The specified time entry is already stopped" ,
264+ )
212265
213266 @classmethod
214267 def checks_owner_and_is_not_started (cls , data : dict ):
215268 cls .check_whether_current_user_owns_item (data )
216269
217270 if data .get ('end_date' ) is None :
218- raise CustomError (HTTPStatus .UNPROCESSABLE_ENTITY , "The specified time entry is already running" )
271+ raise CustomError (
272+ HTTPStatus .UNPROCESSABLE_ENTITY ,
273+ "The specified time entry is already running" ,
274+ )
219275
220276 def get_all (self , conditions : dict = {}) -> list :
221277 event_ctx = self .create_event_context ("read-many" )
222278 conditions .update ({"owner_id" : event_ctx .user_id })
223279
224280 date_range = self .handle_date_filter_args (args = conditions )
225- return self .repository .find_all (event_ctx ,
226- conditions = conditions ,
227- date_range = date_range )
281+ return self .repository .find_all (
282+ event_ctx , conditions = conditions , date_range = date_range
283+ )
228284
229285 def get (self , id ):
230286 event_ctx = self .create_event_context ("read" )
231- return self .repository .find (id , event_ctx , peeker = self .check_whether_current_user_owns_item )
287+ return self .repository .find (
288+ id , event_ctx , peeker = self .check_whether_current_user_owns_item
289+ )
232290
233291 def create (self , data : dict ):
234292 event_ctx = self .create_event_context ("create" )
293+ data ['owner_id' ] = event_ctx .user_id
235294 return self .repository .create (data , event_ctx )
236295
237296 def update (self , id , data : dict , description = None ):
238297 event_ctx = self .create_event_context ("update" , description )
239- return self .repository .partial_update (id , data , event_ctx ,
240- peeker = self .check_whether_current_user_owns_item )
298+ return self .repository .partial_update (
299+ id ,
300+ data ,
301+ event_ctx ,
302+ peeker = self .check_whether_current_user_owns_item ,
303+ )
241304
242305 def stop (self , id ):
243306 event_ctx = self .create_event_context ("update" , "Stop time entry" )
244- return self .repository .partial_update (id , {
245- 'end_date' : current_datetime_str ()
246- }, event_ctx , peeker = self .checks_owner_and_is_not_stopped )
307+ return self .repository .partial_update (
308+ id ,
309+ {'end_date' : current_datetime_str ()},
310+ event_ctx ,
311+ peeker = self .checks_owner_and_is_not_stopped ,
312+ )
247313
248314 def restart (self , id ):
249315 event_ctx = self .create_event_context ("update" , "Restart time entry" )
250- return self .repository .partial_update (id , {
251- 'end_date' : None
252- }, event_ctx , peeker = self .checks_owner_and_is_not_started )
316+ return self .repository .partial_update (
317+ id ,
318+ {'end_date' : None },
319+ event_ctx ,
320+ peeker = self .checks_owner_and_is_not_started ,
321+ )
253322
254323 def delete (self , id ):
255324 event_ctx = self .create_event_context ("delete" )
256- self .repository .delete (id , event_ctx , peeker = self .check_whether_current_user_owns_item )
325+ self .repository .delete (
326+ id , event_ctx , peeker = self .check_whether_current_user_owns_item
327+ )
257328
258329 def find_running (self ):
259330 event_ctx = self .create_event_context ("find_running" )
260- return self .repository .find_running (event_ctx .tenant_id , event_ctx .user_id )
331+ return self .repository .find_running (
332+ event_ctx .tenant_id , event_ctx .user_id
333+ )
261334
262335 @staticmethod
263336 def handle_date_filter_args (args : dict ) -> dict :
0 commit comments