Skip to content

Commit e1ed693

Browse files
committed
fix(time-entries): add owner_id in data when create time-entry
1 parent 1caf8e6 commit e1ed693

File tree

1 file changed

+136
-63
lines changed

1 file changed

+136
-63
lines changed

time_tracker_api/time_entries/time_entries_model.py

Lines changed: 136 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@
55
from azure.cosmos import PartitionKey
66
from 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+
)
1018
from commons.data_access_layer.database import EventContext
1119
from time_tracker_api.database import CRUDDao, APICosmosDBDao
1220
from 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

7280
class 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

195241
class 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

Comments
 (0)