diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 126af423c4..84d27cb117 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -10028,6 +10028,69 @@ paths: description: Success default: description: "" + /namespaces/{ns}/transactions/{txnid}/blockchainevents: + get: + description: 'TODO: Description' + operationId: getTxnBlockchainEvents + parameters: + - description: 'TODO: Description' + in: path + name: ns + required: true + schema: + example: default + type: string + - description: 'TODO: Description' + in: path + name: txnid + required: true + schema: + type: string + - description: Server-side request timeout (millseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 120s + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + id: {} + info: + additionalProperties: {} + type: object + name: + type: string + namespace: + type: string + output: + additionalProperties: {} + type: object + protocolId: + type: string + sequence: + format: int64 + type: integer + source: + type: string + subscription: {} + timestamp: {} + tx: + properties: + id: {} + type: + type: string + type: object + type: object + type: array + description: Success + default: + description: "" /namespaces/{ns}/transactions/{txnid}/operations: get: description: 'TODO: Description' @@ -10060,20 +10123,37 @@ paths: schema: items: properties: + backendId: + type: string created: {} + error: + type: string id: {} + input: + additionalProperties: {} + type: object namespace: type: string + output: + additionalProperties: {} + type: object + plugin: + type: string status: type: string + tx: {} type: enum: - - none - - batch_pin - - token_pool + - blockchain_batch_pin + - publicstorage_batch_broadcast + - dataexchange_batch_send + - dataexchange_blob_send + - token_create_pool + - token_announce_pool - token_transfer - contract_invoke type: string + updated: {} type: object type: array description: Success diff --git a/internal/apiserver/route_get_txn_blockchainevents.go b/internal/apiserver/route_get_txn_blockchainevents.go new file mode 100644 index 0000000000..d3c7a00eed --- /dev/null +++ b/internal/apiserver/route_get_txn_blockchainevents.go @@ -0,0 +1,45 @@ +// Copyright © 2022 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + + "github.com/hyperledger/firefly/internal/config" + "github.com/hyperledger/firefly/internal/i18n" + "github.com/hyperledger/firefly/internal/oapispec" + "github.com/hyperledger/firefly/pkg/fftypes" +) + +var getTxnBlockchainEvents = &oapispec.Route{ + Name: "getTxnBlockchainEvents", + Path: "namespaces/{ns}/transactions/{txnid}/blockchainevents", + Method: http.MethodGet, + PathParams: []*oapispec.PathParam{ + {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, + {Name: "txnid", Description: i18n.MsgTBD}, + }, + QueryParams: nil, + FilterFactory: nil, + Description: i18n.MsgTBD, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return &[]*fftypes.BlockchainEvent{} }, + JSONOutputCodes: []int{http.StatusOK}, + JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + return filterResult(getOr(r.Ctx).GetTransactionBlockchainEvents(r.Ctx, r.PP["ns"], r.PP["txnid"])) + }, +} diff --git a/internal/apiserver/route_get_txn_blockchainevents_test.go b/internal/apiserver/route_get_txn_blockchainevents_test.go new file mode 100644 index 0000000000..ce5955b40c --- /dev/null +++ b/internal/apiserver/route_get_txn_blockchainevents_test.go @@ -0,0 +1,39 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly/pkg/fftypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetTxnBlockchainEvents(t *testing.T) { + o, r := newTestAPIServer() + req := httptest.NewRequest("GET", "/api/v1/namespaces/mynamespace/transactions/abcd12345/blockchainevents", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + o.On("GetTransactionBlockchainEvents", mock.Anything, "mynamespace", "abcd12345"). + Return([]*fftypes.BlockchainEvent{}, nil, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_get_txn_ops.go b/internal/apiserver/route_get_txn_ops.go index 8861244cc5..269e6701fb 100644 --- a/internal/apiserver/route_get_txn_ops.go +++ b/internal/apiserver/route_get_txn_ops.go @@ -37,7 +37,7 @@ var getTxnOps = &oapispec.Route{ FilterFactory: nil, Description: i18n.MsgTBD, JSONInputValue: nil, - JSONOutputValue: func() interface{} { return &[]*fftypes.Transaction{} }, + JSONOutputValue: func() interface{} { return &[]*fftypes.Operation{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { return filterResult(getOr(r.Ctx).GetTransactionOperations(r.Ctx, r.PP["ns"], r.PP["txnid"])) diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 0d0e8a7806..f17e7b4720 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -77,6 +77,7 @@ var routes = []*oapispec.Route{ getSubscriptions, getTxnByID, getTxnOps, + getTxnBlockchainEvents, getTxns, getChartHistogram, diff --git a/internal/orchestrator/data_query.go b/internal/orchestrator/data_query.go index 5efee6aca2..2251262d69 100644 --- a/internal/orchestrator/data_query.go +++ b/internal/orchestrator/data_query.go @@ -294,3 +294,16 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, id *fftypes. func (or *orchestrator) GetBlockchainEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.BlockchainEvent, *database.FilterResult, error) { return or.database.GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) } + +func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, id string) ([]*fftypes.BlockchainEvent, *database.FilterResult, error) { + u, err := or.verifyIDAndNamespace(ctx, ns, id) + if err != nil { + return nil, nil, err + } + fb := database.BlockchainEventQueryFactory.NewFilter(ctx) + filter := fb.And( + fb.Eq("tx.id", u), + fb.Eq("namespace", ns), + ) + return or.database.GetBlockchainEvents(ctx, filter) +} diff --git a/internal/orchestrator/data_query_test.go b/internal/orchestrator/data_query_test.go index fd5b6b03b2..2e05f47fbc 100644 --- a/internal/orchestrator/data_query_test.go +++ b/internal/orchestrator/data_query_test.go @@ -57,7 +57,6 @@ func TestGetTransactionOperationsOk(t *testing.T) { func TestGetTransactionOperationBadID(t *testing.T) { or := newTestOrchestrator() - or.mdi.On("GetOperations", mock.Anything, mock.Anything).Return([]*fftypes.Operation{}, nil, nil) _, _, err := or.GetTransactionOperations(context.Background(), "ns1", "") assert.Regexp(t, "FF10142", err) } @@ -591,3 +590,16 @@ func TestGetBlockchainEvents(t *testing.T) { _, _, err := or.GetBlockchainEvents(context.Background(), "ns", f.And()) assert.NoError(t, err) } + +func TestGetTransactionBlockchainEventsOk(t *testing.T) { + or := newTestOrchestrator() + or.mdi.On("GetBlockchainEvents", mock.Anything, mock.Anything).Return([]*fftypes.BlockchainEvent{}, nil, nil) + _, _, err := or.GetTransactionBlockchainEvents(context.Background(), "ns1", fftypes.NewUUID().String()) + assert.NoError(t, err) +} + +func TestGetTransactionBlockchainEventsBadID(t *testing.T) { + or := newTestOrchestrator() + _, _, err := or.GetTransactionBlockchainEvents(context.Background(), "ns1", "") + assert.Regexp(t, "FF10142", err) +} diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 0a62abdb17..8b12f6ae5c 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -88,6 +88,7 @@ type Orchestrator interface { GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*fftypes.Namespace, *database.FilterResult, error) GetTransactionByID(ctx context.Context, ns, id string) (*fftypes.Transaction, error) GetTransactionOperations(ctx context.Context, ns, id string) ([]*fftypes.Operation, *database.FilterResult, error) + GetTransactionBlockchainEvents(ctx context.Context, ns, id string) ([]*fftypes.BlockchainEvent, *database.FilterResult, error) GetTransactions(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.Transaction, *database.FilterResult, error) GetMessageByID(ctx context.Context, ns, id string) (*fftypes.Message, error) GetMessageByIDWithData(ctx context.Context, ns, id string) (*fftypes.MessageInOut, error) diff --git a/mocks/orchestratormocks/orchestrator.go b/mocks/orchestratormocks/orchestrator.go index d33c08db57..afb4f70f3d 100644 --- a/mocks/orchestratormocks/orchestrator.go +++ b/mocks/orchestratormocks/orchestrator.go @@ -1016,6 +1016,38 @@ func (_m *Orchestrator) GetSubscriptions(ctx context.Context, ns string, filter return r0, r1, r2 } +// GetTransactionBlockchainEvents provides a mock function with given fields: ctx, ns, id +func (_m *Orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns string, id string) ([]*fftypes.BlockchainEvent, *database.FilterResult, error) { + ret := _m.Called(ctx, ns, id) + + var r0 []*fftypes.BlockchainEvent + if rf, ok := ret.Get(0).(func(context.Context, string, string) []*fftypes.BlockchainEvent); ok { + r0 = rf(ctx, ns, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*fftypes.BlockchainEvent) + } + } + + var r1 *database.FilterResult + if rf, ok := ret.Get(1).(func(context.Context, string, string) *database.FilterResult); ok { + r1 = rf(ctx, ns, id) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*database.FilterResult) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok { + r2 = rf(ctx, ns, id) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // GetTransactionByID provides a mock function with given fields: ctx, ns, id func (_m *Orchestrator) GetTransactionByID(ctx context.Context, ns string, id string) (*fftypes.Transaction, error) { ret := _m.Called(ctx, ns, id)