8
8
from bson .errors import InvalidId as BsonInvalidId
9
9
10
10
from todo .dto .responses .error_response import ApiErrorDetail , ApiErrorResponse , ApiErrorSource
11
- from todo .constants .messages import ApiErrors , ValidationErrors
11
+ from todo .constants .messages import ApiErrors , ValidationErrors , AuthErrorMessages
12
12
from todo .exceptions .task_exceptions import TaskNotFoundException
13
+ from .auth_exceptions import TokenExpiredError , TokenMissingError , TokenInvalidError
14
+ from .google_auth_exceptions import (
15
+ GoogleAuthException ,
16
+ GoogleTokenExpiredError ,
17
+ GoogleTokenInvalidError ,
18
+ GoogleRefreshTokenExpiredError ,
19
+ GoogleAPIException ,
20
+ GoogleUserNotFoundException ,
21
+ GoogleTokenMissingError
22
+ )
13
23
14
24
15
25
def format_validation_errors (errors ) -> List [ApiErrorDetail ]:
@@ -37,22 +47,144 @@ def handle_exception(exc, context):
37
47
38
48
error_list = []
39
49
status_code = status .HTTP_500_INTERNAL_SERVER_ERROR
40
- determined_message = ApiErrors .UNEXPECTED_ERROR_OCCURRED
41
50
42
- if isinstance (exc , TaskNotFoundException ):
51
+ if isinstance (exc , TokenExpiredError ):
52
+ status_code = status .HTTP_401_UNAUTHORIZED
53
+ error_list .append (
54
+ ApiErrorDetail (
55
+ source = {ApiErrorSource .HEADER : "Authorization" },
56
+ title = AuthErrorMessages .TOKEN_EXPIRED_TITLE ,
57
+ detail = str (exc ),
58
+ )
59
+ )
60
+ elif isinstance (exc , TokenMissingError ):
61
+ status_code = status .HTTP_401_UNAUTHORIZED
62
+ error_list .append (
63
+ ApiErrorDetail (
64
+ source = {ApiErrorSource .HEADER : "Authorization" },
65
+ title = AuthErrorMessages .AUTHENTICATION_REQUIRED ,
66
+ detail = str (exc ),
67
+ )
68
+ )
69
+ final_response_data = ApiErrorResponse (
70
+ statusCode = status_code ,
71
+ message = str (exc ) if not error_list else error_list [0 ].detail ,
72
+ errors = error_list ,
73
+ authenticated = False ,
74
+ )
75
+ return Response (data = final_response_data .model_dump (mode = "json" , exclude_none = True ), status = status_code )
76
+ elif isinstance (exc , TokenInvalidError ):
77
+ status_code = status .HTTP_401_UNAUTHORIZED
78
+ error_list .append (
79
+ ApiErrorDetail (
80
+ source = {ApiErrorSource .HEADER : "Authorization" },
81
+ title = AuthErrorMessages .INVALID_TOKEN_TITLE ,
82
+ detail = str (exc ),
83
+ )
84
+ )
85
+ final_response_data = ApiErrorResponse (
86
+ statusCode = status_code ,
87
+ message = str (exc ) if not error_list else error_list [0 ].detail ,
88
+ errors = error_list ,
89
+ authenticated = False ,
90
+ )
91
+ return Response (data = final_response_data .model_dump (mode = "json" , exclude_none = True ), status = status_code )
92
+
93
+ elif isinstance (exc , GoogleTokenMissingError ):
94
+ status_code = status .HTTP_401_UNAUTHORIZED
95
+ error_list .append (
96
+ ApiErrorDetail (
97
+ source = {ApiErrorSource .HEADER : "Authorization" },
98
+ title = AuthErrorMessages .AUTHENTICATION_REQUIRED ,
99
+ detail = str (exc ),
100
+ )
101
+ )
102
+ final_response_data = ApiErrorResponse (
103
+ statusCode = status_code ,
104
+ message = str (exc ) if not error_list else error_list [0 ].detail ,
105
+ errors = error_list ,
106
+ authenticated = False ,
107
+ )
108
+ return Response (data = final_response_data .model_dump (mode = "json" , exclude_none = True ), status = status_code )
109
+ elif isinstance (exc , GoogleTokenExpiredError ):
110
+ status_code = status .HTTP_401_UNAUTHORIZED
111
+ error_list .append (
112
+ ApiErrorDetail (
113
+ source = {ApiErrorSource .HEADER : "Authorization" },
114
+ title = AuthErrorMessages .TOKEN_EXPIRED_TITLE ,
115
+ detail = str (exc ),
116
+ )
117
+ )
118
+ final_response_data = ApiErrorResponse (
119
+ statusCode = status_code ,
120
+ message = str (exc ) if not error_list else error_list [0 ].detail ,
121
+ errors = error_list ,
122
+ authenticated = False ,
123
+ )
124
+ return Response (data = final_response_data .model_dump (mode = "json" , exclude_none = True ), status = status_code )
125
+ elif isinstance (exc , GoogleTokenInvalidError ):
126
+ status_code = status .HTTP_401_UNAUTHORIZED
127
+ error_list .append (
128
+ ApiErrorDetail (
129
+ source = {ApiErrorSource .HEADER : "Authorization" },
130
+ title = AuthErrorMessages .INVALID_TOKEN_TITLE ,
131
+ detail = str (exc ),
132
+ )
133
+ )
134
+ final_response_data = ApiErrorResponse (
135
+ statusCode = status_code ,
136
+ message = str (exc ) if not error_list else error_list [0 ].detail ,
137
+ errors = error_list ,
138
+ authenticated = False ,
139
+ )
140
+ return Response (data = final_response_data .model_dump (mode = "json" , exclude_none = True ), status = status_code )
141
+ elif isinstance (exc , GoogleRefreshTokenExpiredError ):
142
+ status_code = status .HTTP_403_FORBIDDEN
143
+ error_list .append (
144
+ ApiErrorDetail (
145
+ source = {ApiErrorSource .HEADER : "Authorization" },
146
+ title = AuthErrorMessages .TOKEN_EXPIRED_TITLE ,
147
+ detail = str (exc ),
148
+ )
149
+ )
150
+ elif isinstance (exc , GoogleAuthException ):
151
+ status_code = status .HTTP_400_BAD_REQUEST
152
+ error_list .append (
153
+ ApiErrorDetail (
154
+ source = {ApiErrorSource .PARAMETER : "google_auth" },
155
+ title = ApiErrors .GOOGLE_AUTH_FAILED ,
156
+ detail = str (exc ),
157
+ )
158
+ )
159
+ elif isinstance (exc , GoogleAPIException ):
160
+ status_code = status .HTTP_500_INTERNAL_SERVER_ERROR
161
+ error_list .append (
162
+ ApiErrorDetail (
163
+ source = {ApiErrorSource .PARAMETER : "google_api" },
164
+ title = ApiErrors .GOOGLE_API_ERROR ,
165
+ detail = str (exc ),
166
+ )
167
+ )
168
+ elif isinstance (exc , GoogleUserNotFoundException ):
169
+ status_code = status .HTTP_404_NOT_FOUND
170
+ error_list .append (
171
+ ApiErrorDetail (
172
+ source = {ApiErrorSource .PARAMETER : "user_id" },
173
+ title = ApiErrors .RESOURCE_NOT_FOUND_TITLE ,
174
+ detail = str (exc ),
175
+ )
176
+ )
177
+ elif isinstance (exc , TaskNotFoundException ):
43
178
status_code = status .HTTP_404_NOT_FOUND
44
- detail_message_str = str (exc )
45
- determined_message = detail_message_str
46
179
error_list .append (
47
180
ApiErrorDetail (
48
181
source = {ApiErrorSource .PATH : "task_id" } if task_id else None ,
49
182
title = ApiErrors .RESOURCE_NOT_FOUND_TITLE ,
50
- detail = detail_message_str ,
183
+ detail = str ( exc ) ,
51
184
)
52
185
)
53
186
elif isinstance (exc , BsonInvalidId ):
54
187
status_code = status .HTTP_400_BAD_REQUEST
55
- determined_message = ValidationErrors .INVALID_TASK_ID_FORMAT
56
188
error_list .append (
57
189
ApiErrorDetail (
58
190
source = {ApiErrorSource .PATH : "task_id" } if task_id else None ,
@@ -67,7 +199,6 @@ def handle_exception(exc, context):
67
199
and (exc .args [0 ] == ValidationErrors .INVALID_TASK_ID_FORMAT or exc .args [0 ] == "Invalid ObjectId format" )
68
200
):
69
201
status_code = status .HTTP_400_BAD_REQUEST
70
- determined_message = ValidationErrors .INVALID_TASK_ID_FORMAT
71
202
error_list .append (
72
203
ApiErrorDetail (
73
204
source = {ApiErrorSource .PATH : "task_id" } if task_id else None ,
@@ -84,7 +215,6 @@ def handle_exception(exc, context):
84
215
)
85
216
elif isinstance (exc , DRFValidationError ):
86
217
status_code = status .HTTP_400_BAD_REQUEST
87
- determined_message = "Invalid request"
88
218
error_list = format_validation_errors (exc .detail )
89
219
if not error_list and exc .detail :
90
220
error_list .append (ApiErrorDetail (detail = str (exc .detail ), title = ApiErrors .VALIDATION_ERROR ))
@@ -94,35 +224,32 @@ def handle_exception(exc, context):
94
224
status_code = response .status_code
95
225
if isinstance (response .data , dict ) and "detail" in response .data :
96
226
detail_str = str (response .data ["detail" ])
97
- determined_message = detail_str
98
227
error_list .append (ApiErrorDetail (detail = detail_str , title = detail_str ))
99
228
elif isinstance (response .data , list ):
100
229
for item_error in response .data :
101
- error_list .append (ApiErrorDetail (detail = str (item_error ), title = determined_message ))
230
+ error_list .append (ApiErrorDetail (detail = str (item_error ), title = str ( exc ) ))
102
231
else :
103
232
error_list .append (
104
233
ApiErrorDetail (
105
234
detail = str (response .data ) if settings .DEBUG else ApiErrors .INTERNAL_SERVER_ERROR ,
106
- title = determined_message ,
235
+ title = str ( exc ) ,
107
236
)
108
237
)
109
238
else :
110
239
error_list .append (
111
- ApiErrorDetail (
112
- detail = str (exc ) if settings .DEBUG else ApiErrors .INTERNAL_SERVER_ERROR , title = determined_message
113
- )
240
+ ApiErrorDetail (detail = str (exc ) if settings .DEBUG else ApiErrors .INTERNAL_SERVER_ERROR , title = str (exc ))
114
241
)
115
242
116
243
if not error_list and not (
117
244
isinstance (exc , ValueError ) and hasattr (exc , "args" ) and exc .args and isinstance (exc .args [0 ], ApiErrorResponse )
118
245
):
119
246
default_detail_str = str (exc ) if settings .DEBUG else ApiErrors .INTERNAL_SERVER_ERROR
120
247
121
- error_list .append (ApiErrorDetail (detail = default_detail_str , title = determined_message ))
248
+ error_list .append (ApiErrorDetail (detail = default_detail_str , title = str ( exc ) ))
122
249
123
250
final_response_data = ApiErrorResponse (
124
251
statusCode = status_code ,
125
- message = determined_message ,
252
+ message = str ( exc ) if not error_list else error_list [ 0 ]. detail ,
126
253
errors = error_list ,
127
254
)
128
255
return Response (data = final_response_data .model_dump (mode = "json" , exclude_none = True ), status = status_code )
0 commit comments