14
14
from todo .dto .responses .create_task_response import CreateTaskResponse
15
15
from todo .dto .responses .error_response import ApiErrorResponse , ApiErrorDetail , ApiErrorSource
16
16
from todo .dto .responses .paginated_response import LinksData
17
+ from todo .exceptions .user_exceptions import UserNotFoundException
17
18
from todo .models .task import TaskModel , DeferredDetailsModel
18
19
from todo .models .common .pyobjectid import PyObjectId
19
20
from todo .repositories .task_repository import TaskRepository
28
29
)
29
30
from bson .errors import InvalidId as BsonInvalidId
30
31
32
+ from todo .repositories .user_repository import UserRepository
33
+
31
34
32
35
@dataclass
33
36
class PaginationConfig :
@@ -112,9 +115,8 @@ def build_page_url(cls, page: int, limit: int) -> str:
112
115
@classmethod
113
116
def prepare_task_dto (cls , task_model : TaskModel ) -> TaskDTO :
114
117
label_dtos = cls ._prepare_label_dtos (task_model .labels ) if task_model .labels else []
115
-
116
118
assignee = cls .prepare_user_dto (task_model .assignee ) if task_model .assignee else None
117
- created_by = cls .prepare_user_dto (task_model .createdBy )
119
+ created_by = cls .prepare_user_dto (task_model .createdBy ) if task_model . createdBy else None
118
120
updated_by = cls .prepare_user_dto (task_model .updatedBy ) if task_model .updatedBy else None
119
121
deferred_details = (
120
122
cls .prepare_deferred_details_dto (task_model .deferredDetails ) if task_model .deferredDetails else None
@@ -172,7 +174,10 @@ def prepare_deferred_details_dto(cls, deferred_details_model: DeferredDetailsMod
172
174
173
175
@classmethod
174
176
def prepare_user_dto (cls , user_id : str ) -> UserDTO :
175
- return UserDTO (id = user_id , name = "SYSTEM" )
177
+ user = UserRepository .get_by_id (user_id )
178
+ if user :
179
+ return UserDTO (id = str (user_id ), name = user .name )
180
+ raise UserNotFoundException (user_id )
176
181
177
182
@classmethod
178
183
def get_task_by_id (cls , task_id : str ) -> TaskDTO :
@@ -208,11 +213,23 @@ def _process_enum_for_update(cls, enum_type: type, value: str | None) -> str | N
208
213
return enum_type [value ].value
209
214
210
215
@classmethod
211
- def update_task (cls , task_id : str , validated_data : dict , user_id : str = "system" ) -> TaskDTO :
216
+ def update_task (cls , task_id : str , validated_data : dict , user_id : str ) -> TaskDTO :
212
217
current_task = TaskRepository .get_by_id (task_id )
218
+
213
219
if not current_task :
214
220
raise TaskNotFoundException (task_id )
215
221
222
+ if current_task .assignee and current_task .assignee != user_id :
223
+ raise PermissionError (ApiErrors .UNAUTHORIZED_TITLE )
224
+
225
+ if not current_task .assignee and current_task .createdBy != user_id :
226
+ raise PermissionError (ApiErrors .UNAUTHORIZED_TITLE )
227
+
228
+ if validated_data .get ("assignee" ):
229
+ assignee_data = UserRepository .get_by_id (validated_data ["assignee" ])
230
+ if not assignee_data :
231
+ raise UserNotFoundException (validated_data ["assignee" ])
232
+
216
233
update_payload = {}
217
234
enum_fields = {"priority" : TaskPriority , "status" : TaskStatus }
218
235
@@ -238,9 +255,16 @@ def update_task(cls, task_id: str, validated_data: dict, user_id: str = "system"
238
255
@classmethod
239
256
def defer_task (cls , task_id : str , deferred_till : datetime , user_id : str ) -> TaskDTO :
240
257
current_task = TaskRepository .get_by_id (task_id )
258
+
241
259
if not current_task :
242
260
raise TaskNotFoundException (task_id )
243
261
262
+ if current_task .assignee and current_task .assignee != user_id :
263
+ raise PermissionError (ApiErrors .UNAUTHORIZED_TITLE )
264
+
265
+ if not current_task .assignee and current_task .createdBy != user_id :
266
+ raise PermissionError (ApiErrors .UNAUTHORIZED_TITLE )
267
+
244
268
if current_task .status == TaskStatus .DONE :
245
269
raise TaskStateConflictException (ValidationErrors .CANNOT_DEFER_A_DONE_TASK )
246
270
@@ -284,6 +308,11 @@ def create_task(cls, dto: CreateTaskDTO) -> CreateTaskResponse:
284
308
now = datetime .now (timezone .utc )
285
309
started_at = now if dto .status == TaskStatus .IN_PROGRESS else None
286
310
311
+ if dto .assignee :
312
+ assignee = UserRepository .get_by_id (dto .assignee )
313
+ if not assignee :
314
+ raise UserNotFoundException (dto .assignee )
315
+
287
316
if dto .labels :
288
317
existing_labels = LabelRepository .list_by_ids (dto .labels )
289
318
if len (existing_labels ) != len (dto .labels ):
@@ -317,7 +346,7 @@ def create_task(cls, dto: CreateTaskDTO) -> CreateTaskResponse:
317
346
createdAt = now ,
318
347
isAcknowledged = False ,
319
348
isDeleted = False ,
320
- createdBy = "system" , # placeholder, will be user_id when auth is in place
349
+ createdBy = dto . createdBy , # placeholder, will be user_id when auth is in place
321
350
)
322
351
323
352
try :
@@ -356,8 +385,8 @@ def create_task(cls, dto: CreateTaskDTO) -> CreateTaskResponse:
356
385
)
357
386
358
387
@classmethod
359
- def delete_task (cls , task_id : str ) -> None :
360
- deleted_task_model = TaskRepository .delete_by_id (task_id )
388
+ def delete_task (cls , task_id : str , user_id : str ) -> None :
389
+ deleted_task_model = TaskRepository .delete_by_id (task_id , user_id )
361
390
if deleted_task_model is None :
362
391
raise TaskNotFoundException (task_id )
363
392
return None
0 commit comments