|
4 | 4 | from django.core.exceptions import ValidationError
|
5 | 5 | from django.urls import reverse_lazy
|
6 | 6 | from urllib.parse import urlencode
|
| 7 | +from datetime import datetime, timezone |
7 | 8 |
|
8 | 9 | from todo.dto.label_dto import LabelDTO
|
9 |
| -from todo.dto.task_dto import TaskDTO |
| 10 | +from todo.dto.task_dto import TaskDTO, CreateTaskDTO |
10 | 11 | from todo.dto.user_dto import UserDTO
|
11 | 12 | from todo.dto.responses.get_tasks_response import GetTasksResponse
|
| 13 | +from todo.dto.responses.create_task_response import CreateTaskResponse |
| 14 | +from todo.dto.responses.error_response import ApiErrorResponse, ApiErrorDetail, ApiErrorSource |
12 | 15 | from todo.dto.responses.paginated_response import LinksData
|
13 | 16 | from todo.models.task import TaskModel
|
14 | 17 | from todo.repositories.task_repository import TaskRepository
|
15 | 18 | from todo.repositories.label_repository import LabelRepository
|
| 19 | +from todo.constants.task import TaskStatus |
| 20 | +from todo.constants.messages import ApiErrors, ValidationErrors |
16 | 21 | from django.conf import settings
|
17 | 22 |
|
18 | 23 |
|
@@ -141,3 +146,78 @@ def _prepare_label_dtos(cls, label_ids: List[str]) -> List[LabelDTO]:
|
141 | 146 | @classmethod
|
142 | 147 | def prepare_user_dto(cls, user_id: str) -> UserDTO:
|
143 | 148 | return UserDTO(id=user_id, name="SYSTEM")
|
| 149 | + |
| 150 | + @classmethod |
| 151 | + def create_task(cls, dto: CreateTaskDTO) -> CreateTaskResponse: |
| 152 | + now = datetime.now(timezone.utc) |
| 153 | + started_at = now if dto.status == TaskStatus.IN_PROGRESS else None |
| 154 | + |
| 155 | + if dto.labels: |
| 156 | + existing_labels = LabelRepository.list_by_ids(dto.labels) |
| 157 | + if len(existing_labels) != len(dto.labels): |
| 158 | + found_ids = [str(label.id) for label in existing_labels] |
| 159 | + missing_ids = [label_id for label_id in dto.labels if label_id not in found_ids] |
| 160 | + |
| 161 | + raise ValueError( |
| 162 | + ApiErrorResponse( |
| 163 | + statusCode=400, |
| 164 | + message=ApiErrors.INVALID_LABELS, |
| 165 | + errors=[ |
| 166 | + ApiErrorDetail( |
| 167 | + source={ApiErrorSource.PARAMETER: "labels"}, |
| 168 | + title=ApiErrors.INVALID_LABEL_IDS, |
| 169 | + detail=ValidationErrors.MISSING_LABEL_IDS.format(", ".join(missing_ids)), |
| 170 | + ) |
| 171 | + ], |
| 172 | + ) |
| 173 | + ) |
| 174 | + |
| 175 | + task = TaskModel( |
| 176 | + title=dto.title, |
| 177 | + description=dto.description, |
| 178 | + priority=dto.priority, |
| 179 | + status=dto.status, |
| 180 | + assignee=dto.assignee, |
| 181 | + labels=dto.labels, |
| 182 | + dueAt=dto.dueAt, |
| 183 | + startedAt=started_at, |
| 184 | + createdAt=now, |
| 185 | + isAcknowledged=False, |
| 186 | + isDeleted=False, |
| 187 | + createdBy="system", # placeholder, will be user_id when auth is in place |
| 188 | + ) |
| 189 | + |
| 190 | + try: |
| 191 | + created_task = TaskRepository.create(task) |
| 192 | + task_dto = cls.prepare_task_dto(created_task) |
| 193 | + return CreateTaskResponse(data=task_dto) |
| 194 | + except ValueError as e: |
| 195 | + if isinstance(e.args[0], ApiErrorResponse): |
| 196 | + raise e |
| 197 | + raise ValueError( |
| 198 | + ApiErrorResponse( |
| 199 | + statusCode=500, |
| 200 | + message=ApiErrors.REPOSITORY_ERROR, |
| 201 | + errors=[ |
| 202 | + ApiErrorDetail( |
| 203 | + source={ApiErrorSource.PARAMETER: "task_repository"}, |
| 204 | + title=ApiErrors.UNEXPECTED_ERROR, |
| 205 | + detail=str(e) if settings.DEBUG else ApiErrors.INTERNAL_SERVER_ERROR, |
| 206 | + ) |
| 207 | + ], |
| 208 | + ) |
| 209 | + ) |
| 210 | + except Exception as e: |
| 211 | + raise ValueError( |
| 212 | + ApiErrorResponse( |
| 213 | + statusCode=500, |
| 214 | + message=ApiErrors.SERVER_ERROR, |
| 215 | + errors=[ |
| 216 | + ApiErrorDetail( |
| 217 | + source={ApiErrorSource.PARAMETER: "server"}, |
| 218 | + title=ApiErrors.UNEXPECTED_ERROR, |
| 219 | + detail=str(e) if settings.DEBUG else ApiErrors.INTERNAL_SERVER_ERROR, |
| 220 | + ) |
| 221 | + ], |
| 222 | + ) |
| 223 | + ) |
0 commit comments