feat(conversations): align transcript delivery

This commit is contained in:
2026-06-07 12:08:53 +08:00
parent 83878eb606
commit bec65a86e4
12 changed files with 461 additions and 24 deletions
@@ -721,6 +721,14 @@ func (h *ConversationHandler) Transcript(c *gin.Context) {
return
}
if svcErr := h.conversationSvc.SendTranscript(c.Request.Context(), accountID, conversation.ID, req.Email); svcErr != nil {
if errors.Is(svcErr, service.ErrEmailTranscriptDisabled) {
c.JSON(http.StatusPaymentRequired, gin.H{"error": "Email transcript is not available on your plan"})
return
}
if errors.Is(svcErr, service.ErrEmailRateLimited) {
c.Status(http.StatusTooManyRequests)
return
}
handleServiceError(c, svcErr)
return
}
@@ -14,6 +14,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"gorm.io/datatypes"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
@@ -395,6 +396,46 @@ func (s *ConversationHandlerTestSuite) TestTranscript_InvalidEmail() {
assert.Empty(s.T(), w.Body.String())
}
func (s *ConversationHandlerTestSuite) TestTranscript_PaymentRequiredWhenDisabled() {
s.Require().NoError(s.db.Model(s.testAccount).Updates(map[string]any{
"limits": datatypes.JSON(`{"email_transcript_enabled":false}`),
"custom_attributes": datatypes.JSON(`{}`),
}).Error)
s.T().Cleanup(func() {
_ = s.db.Model(s.testAccount).Updates(map[string]any{"limits": datatypes.JSON(`{}`), "custom_attributes": datatypes.JSON(`{}`)}).Error
})
bodyBytes, _ := json.Marshal(map[string]string{"email": "test@example.com"})
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", s.accountURL()+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/transcript", bytes.NewReader(bodyBytes))
req.Header.Set("Content-Type", "application/json")
s.router.ServeHTTP(w, req)
assert.Equal(s.T(), http.StatusPaymentRequired, w.Code)
var resp map[string]any
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(s.T(), "Email transcript is not available on your plan", resp["error"])
}
func (s *ConversationHandlerTestSuite) TestTranscript_TooManyRequestsWhenRateLimited() {
s.Require().NoError(s.db.Model(s.testAccount).Updates(map[string]any{
"limits": datatypes.JSON(`{"emails":1}`),
"custom_attributes": datatypes.JSON(`{"_outbound_email_count":{"date":"` + time.Now().Format("2006-01-02") + `","count":1}}`),
}).Error)
s.T().Cleanup(func() {
_ = s.db.Model(s.testAccount).Updates(map[string]any{"limits": datatypes.JSON(`{}`), "custom_attributes": datatypes.JSON(`{}`)}).Error
})
bodyBytes, _ := json.Marshal(map[string]string{"email": "test@example.com"})
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", s.accountURL()+"/conversations/"+strconv.FormatUint(uint64(s.testConv.ID), 10)+"/transcript", bytes.NewReader(bodyBytes))
req.Header.Set("Content-Type", "application/json")
s.router.ServeHTTP(w, req)
assert.Equal(s.T(), http.StatusTooManyRequests, w.Code)
assert.Empty(s.T(), w.Body.String())
}
func (s *ConversationHandlerTestSuite) TestTranscript_ConversationNotFound() {
body := map[string]string{"email": "test@example.com"}
bodyBytes, _ := json.Marshal(body)