5
5
from azure .cosmos import PartitionKey
6
6
from flask_restplus ._http import HTTPStatus
7
7
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
+ )
10
18
from commons .data_access_layer .database import EventContext
11
19
from time_tracker_api .database import CRUDDao , APICosmosDBDao
12
20
from time_tracker_api .security import current_user_id
@@ -34,10 +42,8 @@ def restart(self, id: str):
34
42
'id' : 'time_entry' ,
35
43
'partition_key' : PartitionKey (path = '/tenant_id' ),
36
44
'unique_key_policy' : {
37
- 'uniqueKeys' : [
38
- {'paths' : ['/owner_id' , '/end_date' , '/deleted' ]},
39
- ]
40
- }
45
+ 'uniqueKeys' : [{'paths' : ['/owner_id' , '/end_date' , '/deleted' ]}]
46
+ },
41
47
}
42
48
43
49
@@ -66,15 +72,20 @@ def __repr__(self):
66
72
return '<Time Entry %r>' % self .start_date # pragma: no cover
67
73
68
74
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
70
78
71
79
72
80
class TimeEntryCosmosDBRepository (CosmosDBRepository ):
73
81
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
+ )
78
89
79
90
@staticmethod
80
91
def create_sql_ignore_id_condition (id : str ):
@@ -93,7 +104,9 @@ def create_sql_date_range_filter(date_range: dict) -> str:
93
104
else :
94
105
return ''
95
106
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
+ ):
97
110
custom_sql_conditions = []
98
111
custom_sql_conditions .append (
99
112
self .create_sql_date_range_filter (date_range )
@@ -106,9 +119,9 @@ def find_all(self, event_context: EventContext, conditions: dict, date_range: di
106
119
event_context = event_context ,
107
120
conditions = conditions ,
108
121
custom_sql_conditions = custom_sql_conditions ,
109
- custom_params = custom_params
122
+ custom_params = custom_params ,
110
123
)
111
-
124
+
112
125
def on_create (self , new_item_data : dict , event_context : EventContext ):
113
126
CosmosDBRepository .on_create (self , new_item_data , event_context )
114
127
@@ -122,8 +135,16 @@ def on_update(self, updated_item_data: dict, event_context: EventContext):
122
135
self .validate_data (updated_item_data , event_context )
123
136
self .replace_empty_value_per_none (updated_item_data )
124
137
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
+ ):
127
148
conditions = {
128
149
"owner_id" : owner_id ,
129
150
"tenant_id" : tenant_id ,
@@ -136,37 +157,54 @@ def find_interception_with_date_range(self, start_date, end_date, owner_id, tena
136
157
params .extend (self .generate_params (conditions ))
137
158
result = self .container .query_items (
138
159
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
+ ),
146
177
parameters = params ,
147
- partition_key = tenant_id )
178
+ partition_key = tenant_id ,
179
+ )
148
180
149
181
function_mapper = self .get_mapper_or_dict (mapper )
150
182
return list (map (function_mapper , result ))
151
183
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
+ ):
153
187
conditions = {
154
188
"owner_id" : owner_id ,
155
189
"tenant_id" : tenant_id ,
156
190
}
157
191
result = self .container .query_items (
158
192
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
163
198
""" .format (
164
- visibility_condition = self .create_sql_condition_for_visibility (True ),
199
+ visibility_condition = self .create_sql_condition_for_visibility (
200
+ True
201
+ ),
165
202
conditions_clause = self .create_sql_where_conditions (conditions ),
166
203
),
167
204
parameters = self .generate_params (conditions ),
168
205
partition_key = tenant_id ,
169
- max_item_count = 1 )
206
+ max_item_count = 1 ,
207
+ )
170
208
171
209
function_mapper = self .get_mapper_or_dict (mapper )
172
210
return function_mapper (next (result ))
@@ -176,20 +214,28 @@ def validate_data(self, data, event_context: EventContext):
176
214
177
215
if data .get ('end_date' ) is not None :
178
216
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
+ )
181
221
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
+ )
190
234
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
+ )
193
239
194
240
195
241
class TimeEntriesCosmosDBDao (APICosmosDBDao , TimeEntriesDao ):
@@ -198,66 +244,93 @@ def __init__(self, repository):
198
244
199
245
@classmethod
200
246
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
+ )
205
255
206
256
@classmethod
207
257
def checks_owner_and_is_not_stopped (cls , data : dict ):
208
258
cls .check_whether_current_user_owns_item (data )
209
259
210
260
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
+ )
212
265
213
266
@classmethod
214
267
def checks_owner_and_is_not_started (cls , data : dict ):
215
268
cls .check_whether_current_user_owns_item (data )
216
269
217
270
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
+ )
219
275
220
276
def get_all (self , conditions : dict = {}) -> list :
221
277
event_ctx = self .create_event_context ("read-many" )
222
278
conditions .update ({"owner_id" : event_ctx .user_id })
223
279
224
280
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
+ )
228
284
229
285
def get (self , id ):
230
286
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
+ )
232
290
233
291
def create (self , data : dict ):
234
292
event_ctx = self .create_event_context ("create" )
293
+ data ['owner_id' ] = event_ctx .user_id
235
294
return self .repository .create (data , event_ctx )
236
295
237
296
def update (self , id , data : dict , description = None ):
238
297
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
+ )
241
304
242
305
def stop (self , id ):
243
306
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
+ )
247
313
248
314
def restart (self , id ):
249
315
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
+ )
253
322
254
323
def delete (self , id ):
255
324
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
+ )
257
328
258
329
def find_running (self ):
259
330
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
+ )
261
334
262
335
@staticmethod
263
336
def handle_date_filter_args (args : dict ) -> dict :
0 commit comments