From b3bfb2bc3d952650875696e1abe5db7046c4cfd1 Mon Sep 17 00:00:00 2001 From: hanif salafi Date: Tue, 4 Nov 2025 10:15:21 +0700 Subject: [PATCH] fix: update audit_trails, ai-chat --- app/middleware/audit_trails.middleware.go | 43 +++++++++++++++++-- .../ai_chat/controller/ai_chat.controller.go | 4 +- docs/swagger/docs.go | 8 ++-- docs/swagger/swagger.json | 8 ++-- docs/swagger/swagger.yaml | 4 +- 5 files changed, 49 insertions(+), 18 deletions(-) diff --git a/app/middleware/audit_trails.middleware.go b/app/middleware/audit_trails.middleware.go index 4c62753..5e7a85b 100644 --- a/app/middleware/audit_trails.middleware.go +++ b/app/middleware/audit_trails.middleware.go @@ -23,22 +23,59 @@ func AuditTrailsMiddleware(db *gorm.DB) fiber.Handler { authHeader := c.Get("Authorization") userId := utilSvc.GetUserId(authHeader) + // Execute the next handler err := c.Next() + // Get status code - ensure it's set correctly for errors + statusCode := c.Response().StatusCode() + if err != nil { + // If error occurred, ensure status code reflects the error + // The error handler should have set this, but if not, default to 500 + if statusCode == fiber.StatusOK || statusCode == 0 { + statusCode = fiber.StatusInternalServerError + } + } + + // Get response body + responseBody := c.Response().Body() + + // If response body is empty and there's an error, create error response + if len(responseBody) == 0 && err != nil { + // Create error response JSON matching the error handler format + errorResp := map[string]interface{}{ + "success": false, + "code": statusCode, + "message": err.Error(), + } + if errorJSON, marshalErr := json.Marshal(errorResp); marshalErr == nil { + responseBody = errorJSON + } else { + responseBody = []byte(err.Error()) + } + } + audit := entity.AuditTrails{ Method: c.Method(), Path: c.OriginalURL(), IP: getIP(c), - Status: c.Response().StatusCode(), + Status: statusCode, UserID: userId, RequestHeaders: string(headersJSON), RequestBody: string(requestBody), - ResponseBody: string(c.Response().Body()), + ResponseBody: string(responseBody), DurationMs: time.Since(start).Milliseconds(), CreatedAt: time.Now(), } - go db.Create(&audit) + // Save audit trail - use goroutine to avoid blocking + // IMPORTANT: Save synchronously to ensure it completes even if app crashes + // Using goroutine but with proper error handling + go func(auditRecord entity.AuditTrails) { + if saveErr := db.Create(&auditRecord).Error; saveErr != nil { + log.Printf("Failed to save audit trail for %s %s (status: %d): %v", + auditRecord.Method, auditRecord.Path, auditRecord.Status, saveErr) + } + }(audit) return err } diff --git a/app/module/ai_chat/controller/ai_chat.controller.go b/app/module/ai_chat/controller/ai_chat.controller.go index 917cb62..ad69ae9 100644 --- a/app/module/ai_chat/controller/ai_chat.controller.go +++ b/app/module/ai_chat/controller/ai_chat.controller.go @@ -120,7 +120,7 @@ func (_i *aiChatController) GetSession(c *fiber.Ctx) error { // @Description API for create AI chat session // @Tags AI Chat // @Security Bearer -// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token" // @Param Authorization header string false "Insert your access token" default(Bearer ) // @Param payload body request.AIChatSessionsCreateRequest true "Required payload" // @Success 200 {object} response.Response @@ -154,7 +154,7 @@ func (_i *aiChatController) CreateSession(c *fiber.Ctx) error { // @Tags AI Chat // @Security Bearer // @Param Authorization header string false "Insert your access token" default(Bearer ) -// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token" // @Param id path int true "Session ID" // @Param payload body request.AIChatSessionsUpdateRequest true "Required payload" // @Success 200 {object} response.Response diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index 4cae6b7..a755ad3 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -1173,8 +1173,7 @@ const docTemplate = `{ "type": "string", "description": "Insert the X-Csrf-Token", "name": "X-Csrf-Token", - "in": "header", - "required": true + "in": "header" }, { "type": "string", @@ -1497,8 +1496,7 @@ const docTemplate = `{ "type": "string", "description": "Insert the X-Csrf-Token", "name": "X-Csrf-Token", - "in": "header", - "required": true + "in": "header" }, { "type": "integer", @@ -15584,12 +15582,12 @@ const docTemplate = `{ "request.ChatScheduleCreateRequest": { "type": "object", "required": [ - "chat_session_id", "scheduled_at", "title" ], "properties": { "chat_session_id": { + "description": "Optional - if empty, will create new chat session", "type": "integer" }, "description": { diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index 00ea046..96a8c63 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -1162,8 +1162,7 @@ "type": "string", "description": "Insert the X-Csrf-Token", "name": "X-Csrf-Token", - "in": "header", - "required": true + "in": "header" }, { "type": "string", @@ -1486,8 +1485,7 @@ "type": "string", "description": "Insert the X-Csrf-Token", "name": "X-Csrf-Token", - "in": "header", - "required": true + "in": "header" }, { "type": "integer", @@ -15573,12 +15571,12 @@ "request.ChatScheduleCreateRequest": { "type": "object", "required": [ - "chat_session_id", "scheduled_at", "title" ], "properties": { "chat_session_id": { + "description": "Optional - if empty, will create new chat session", "type": "integer" }, "description": { diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 303343f..1c60699 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -410,6 +410,7 @@ definitions: request.ChatScheduleCreateRequest: properties: chat_session_id: + description: Optional - if empty, will create new chat session type: integer description: maxLength: 1000 @@ -434,7 +435,6 @@ definitions: minLength: 3 type: string required: - - chat_session_id - scheduled_at - title type: object @@ -2080,7 +2080,6 @@ paths: - description: Insert the X-Csrf-Token in: header name: X-Csrf-Token - required: true type: string - default: Bearer description: Insert your access token @@ -2202,7 +2201,6 @@ paths: - description: Insert the X-Csrf-Token in: header name: X-Csrf-Token - required: true type: string - description: Session ID in: path