Skip to content

Commit 50af40b

Browse files
authored
fix: ensure envelope can only be set to nil for transfers (#259)
1 parent 3a91b79 commit 50af40b

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

pkg/controllers/transaction.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,34 @@ func UpdateTransaction(c *gin.Context) {
226226
return
227227
}
228228

229+
// Check the source account
230+
sourceAccountID := transaction.SourceAccountID
231+
if data.SourceAccountID != uuid.Nil {
232+
sourceAccountID = data.SourceAccountID
233+
}
234+
sourceAccount, err := getAccountResource(c, sourceAccountID)
235+
if err != nil {
236+
return
237+
}
238+
239+
// Check the destination account
240+
destinationAccountID := transaction.DestinationAccountID
241+
if data.DestinationAccountID != uuid.Nil {
242+
destinationAccountID = data.DestinationAccountID
243+
}
244+
destinationAccount, err := getAccountResource(c, destinationAccountID)
245+
if err != nil {
246+
return
247+
}
248+
249+
// Check if the transaction is a transfer. If yes, the envelope can be empty.
250+
//
251+
// Check that the Envelope ID is set for incoming and outgoing transactions
252+
if sourceAccount.External || destinationAccount.External && data.EnvelopeID == nil {
253+
httputil.NewError(c, http.StatusBadRequest, errors.New("For incoming and outgoing transactions, an envelope is required"))
254+
return
255+
}
256+
229257
err = database.DB.Model(&transaction).Select("", updateFields...).Updates(data).Error
230258
if err != nil {
231259
httputil.ErrorHandler(c, err)

pkg/controllers/transaction_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,36 @@ func (suite *TestSuiteEnv) TestUpdateTransactionNegativeAmount() {
281281
test.AssertHTTPStatus(suite.T(), http.StatusBadRequest, &recorder)
282282
}
283283

284+
func (suite *TestSuiteEnv) TestUpdateTransactionEmptySourceDestinationAccount() {
285+
transaction := createTestTransaction(suite.T(), models.TransactionCreate{Amount: decimal.NewFromFloat(382.18)})
286+
287+
recorder := test.Request(suite.T(), http.MethodPatch, transaction.Data.Links.Self, models.TransactionCreate{SourceAccountID: uuid.New()})
288+
test.AssertHTTPStatus(suite.T(), http.StatusNotFound, &recorder)
289+
290+
recorder = test.Request(suite.T(), http.MethodPatch, transaction.Data.Links.Self, models.TransactionCreate{DestinationAccountID: uuid.New()})
291+
test.AssertHTTPStatus(suite.T(), http.StatusNotFound, &recorder)
292+
}
293+
294+
func (suite *TestSuiteEnv) TestUpdateNoEnvelopeTransactionOutgoing() {
295+
envelope := createTestEnvelope(suite.T(), models.EnvelopeCreate{})
296+
297+
c := models.TransactionCreate{
298+
BudgetID: createTestBudget(suite.T(), models.BudgetCreate{Name: "Testing budget for updating of outgoing transfer"}).Data.ID,
299+
SourceAccountID: createTestAccount(suite.T(), models.AccountCreate{Name: "Internal Source Account", External: false}).Data.ID,
300+
DestinationAccountID: createTestAccount(suite.T(), models.AccountCreate{Name: "External destination account", External: true}).Data.ID,
301+
EnvelopeID: &envelope.Data.ID,
302+
Amount: decimal.NewFromFloat(984.13),
303+
}
304+
305+
transaction := createTestTransaction(suite.T(), c)
306+
307+
recorder := test.Request(suite.T(), http.MethodPatch, transaction.Data.Links.Self, `{ "envelopeId": null }`)
308+
test.AssertHTTPStatus(suite.T(), http.StatusBadRequest, &recorder)
309+
310+
err := test.DecodeError(suite.T(), recorder.Body.Bytes())
311+
assert.Equal(suite.T(), "For incoming and outgoing transactions, an envelope is required", err, "request id %s", recorder.Header().Get("x-request-id"))
312+
}
313+
284314
func (suite *TestSuiteEnv) TestUpdateNonExistingTransaction() {
285315
recorder := test.Request(suite.T(), http.MethodPatch, "http://example.com/v1/transactions/6ae3312c-23cf-4225-9a81-4f218ba41b00", `{ "note": "2" }`)
286316
test.AssertHTTPStatus(suite.T(), http.StatusNotFound, &recorder)

pkg/httputil/query_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,26 @@ func TestGetBodyFields(t *testing.T) {
4141
assert.Equal(t, http.StatusOK, w.Code, "Status is wrong, return body %#v", w.Body.String())
4242
}
4343

44+
func TestGetBodyFieldsNull(t *testing.T) {
45+
w := httptest.NewRecorder()
46+
c, r := gin.CreateTestContext(w)
47+
48+
r.PATCH("/", func(ctx *gin.Context) {
49+
fields, err := httputil.GetBodyFields(c, models.AccountCreate{})
50+
if err != nil {
51+
c.JSON(http.StatusBadRequest, err)
52+
}
53+
c.JSON(http.StatusOK, fields)
54+
})
55+
56+
json := []byte(`{ "name": null }`)
57+
58+
c.Request, _ = http.NewRequest(http.MethodPatch, "https://example.com/", bytes.NewBuffer(json))
59+
r.ServeHTTP(w, c.Request)
60+
assert.Equal(t, http.StatusOK, w.Code, "Status is wrong, return body %#v", w.Body.String())
61+
assert.Equal(t, `["Name"]`, w.Body.String(), `Fields are not parsed correctly, should be ["Name"]`)
62+
}
63+
4464
func TestGetBodyFieldsUnparseable(t *testing.T) {
4565
w := httptest.NewRecorder()
4666
c, r := gin.CreateTestContext(w)

0 commit comments

Comments
 (0)