feat(automation): align attachment uploads
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"github.com/gochat/gochat/internal/automation"
|
||||
"github.com/gochat/gochat/internal/model"
|
||||
)
|
||||
|
||||
// automationDBProvider wraps *gorm.DB to implement automation.DBProvider.
|
||||
@@ -40,7 +41,7 @@ func (s *AutomationRuleHandlerTestSuite) SetupSuite() {
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
s.Require().NoError(err, "failed to open SQLite test database")
|
||||
s.Require().NoError(db.AutoMigrate(&automation.AutomationRule{}), "failed to auto-migrate AutomationRule model")
|
||||
s.Require().NoError(db.AutoMigrate(&automation.AutomationRule{}, &model.DirectUpload{}), "failed to auto-migrate AutomationRule model")
|
||||
s.db = db
|
||||
|
||||
provider := &automationDBProvider{db: db}
|
||||
@@ -74,6 +75,7 @@ func (s *AutomationRuleHandlerTestSuite) TearDownSuite() {
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) SetupTest() {
|
||||
s.db.Exec("DELETE FROM automation_rules")
|
||||
s.db.Exec("DELETE FROM direct_uploads")
|
||||
}
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) createRule(accountID uint, eventName, name string, active bool) *automation.AutomationRule {
|
||||
@@ -192,6 +194,53 @@ func (s *AutomationRuleHandlerTestSuite) TestCreate_Success() {
|
||||
s.Equal(float64(1), saved.Actions[0].ActionParams["team_id"])
|
||||
}
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) TestCreate_AttachmentActionAcceptsSignedUploadAndSerializesFiles() {
|
||||
upload := &model.DirectUpload{
|
||||
UploadUUID: "automation-upload-signed-id",
|
||||
AccountID: 1,
|
||||
Status: model.DirectUploadStatusPending,
|
||||
Source: model.DirectUploadSourceAccount,
|
||||
OriginalName: "automation.pdf",
|
||||
FileType: "file",
|
||||
MimeType: "application/pdf",
|
||||
FileSize: 321,
|
||||
FileURL: "/uploads/account/1/automation.pdf",
|
||||
}
|
||||
s.Require().NoError(s.db.Create(upload).Error)
|
||||
body := `{"event_name":"conversation_created","name":"Send file","active":true,"conditions":[],"actions":[{"action_name":"send_attachment","action_params":["automation-upload-signed-id"]}]}`
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/accounts/1/automation_rules", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
s.Equal(http.StatusOK, w.Code)
|
||||
|
||||
var resp map[string]interface{}
|
||||
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
|
||||
action := resp["actions"].([]interface{})[0].(map[string]interface{})
|
||||
s.Equal([]interface{}{float64(upload.ID)}, action["action_params"])
|
||||
files := resp["files"].([]interface{})
|
||||
s.Require().Len(files, 1)
|
||||
file := files[0].(map[string]interface{})
|
||||
s.Equal(float64(upload.ID), file["blob_id"])
|
||||
s.Equal(resp["id"], file["automation_rule_id"])
|
||||
s.Equal("automation.pdf", file["filename"])
|
||||
}
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) TestCreate_AttachmentActionRejectsInvalidBlob() {
|
||||
body := `{"event_name":"conversation_created","name":"Bad file","active":true,"conditions":[],"actions":[{"action_name":"send_attachment","action_params":["missing-upload"]}]}`
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/accounts/1/automation_rules", bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
s.Equal(http.StatusUnprocessableEntity, w.Code)
|
||||
|
||||
var resp map[string]interface{}
|
||||
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
|
||||
s.Equal("invalid attachment", resp["error"])
|
||||
}
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) TestCreate_InvalidJSON() {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/accounts/1/automation_rules", bytes.NewBufferString(`{invalid`))
|
||||
@@ -234,6 +283,28 @@ func (s *AutomationRuleHandlerTestSuite) TestUpdate_Success() {
|
||||
s.Equal("UpdatedName", saved.Name)
|
||||
}
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) TestUpdate_OmittedActionsPreservesExistingActions() {
|
||||
rule := s.createRule(1, "conversation_created", "KeepActions", true)
|
||||
|
||||
body := `{"event_name":"message_created","name":"Renamed","active":false,"conditions":[{"attribute_key":"status","filter_operator":"equal_to","values":["resolved"],"query_operator":"and"}]}`
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodPut, fmt.Sprintf("/api/v1/accounts/1/automation_rules/%d", rule.ID), bytes.NewBufferString(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
s.router.ServeHTTP(w, req)
|
||||
s.Equal(http.StatusOK, w.Code)
|
||||
|
||||
var resp map[string]interface{}
|
||||
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
|
||||
payload := resp["payload"].(map[string]interface{})
|
||||
action := payload["actions"].([]interface{})[0].(map[string]interface{})
|
||||
s.Equal("assign_team", action["action_name"])
|
||||
s.Equal([]interface{}{float64(1)}, action["action_params"])
|
||||
|
||||
var saved automation.AutomationRule
|
||||
s.Require().NoError(s.db.First(&saved, rule.ID).Error)
|
||||
s.Equal(float64(1), saved.Actions[0].ActionParams["team_id"])
|
||||
}
|
||||
|
||||
func (s *AutomationRuleHandlerTestSuite) TestUpdate_InvalidID() {
|
||||
body := `{"name":"Updated","active":true}`
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
Reference in New Issue
Block a user