From 1064d857dd40bfd1cf2a58fe61faee8c1268e8c4 Mon Sep 17 00:00:00 2001 From: Janis Saldabols Date: Tue, 10 Feb 2026 17:12:03 +0200 Subject: [PATCH 1/2] ILLDEV-277 Add patron request events endpoint --- broker/app/app.go | 2 +- broker/events/eventrepo.go | 12 +++ broker/oapi/open-api.yaml | 40 +++++++++ broker/patron_request/api/api-handler.go | 57 ++++++++++++- broker/patron_request/api/api-handler_test.go | 84 ++++++++++++++----- broker/sqlc/event_query.sql | 6 ++ broker/test/mocks/mock_eventrepo.go | 11 +++ .../patron_request/api/api-handler_test.go | 14 ++++ 8 files changed, 201 insertions(+), 25 deletions(-) diff --git a/broker/app/app.go b/broker/app/app.go index 1c7ca8bd..5eed645c 100644 --- a/broker/app/app.go +++ b/broker/app/app.go @@ -162,7 +162,7 @@ func Init(ctx context.Context) (Context, error) { workflowManager := service.CreateWorkflowManager(eventBus, illRepo, service.WorkflowConfig{}) lmsCreator := lms.NewLmsCreator(illRepo, dirAdapter) prActionService := prservice.CreatePatronRequestActionService(prRepo, eventBus, &iso18626Handler, lmsCreator) - prApiHandler := prapi.NewPrApiHandler(prRepo, eventBus, common.NewTenant(TENANT_TO_SYMBOL), API_PAGE_SIZE) + prApiHandler := prapi.NewPrApiHandler(prRepo, eventBus, eventRepo, common.NewTenant(TENANT_TO_SYMBOL), API_PAGE_SIZE) sseBroker := api.NewSseBroker(appCtx, common.NewTenant(TENANT_TO_SYMBOL)) diff --git a/broker/events/eventrepo.go b/broker/events/eventrepo.go index 160e83ad..5d673a68 100644 --- a/broker/events/eventrepo.go +++ b/broker/events/eventrepo.go @@ -19,6 +19,7 @@ type EventRepo interface { GetIllTransactionEvents(ctx common.ExtendedContext, id string) ([]Event, int64, error) DeleteEventsByIllTransaction(ctx common.ExtendedContext, illTransId string) error GetLatestRequestEventByAction(ctx common.ExtendedContext, illTransId string, action string) (Event, error) + GetPatronRequestEvents(ctx common.ExtendedContext, id string) ([]Event, error) } type PgEventRepo struct { @@ -91,6 +92,17 @@ func (r *PgEventRepo) GetIllTransactionEvents(ctx common.ExtendedContext, id str return events, fullCount, err } +func (r *PgEventRepo) GetPatronRequestEvents(ctx common.ExtendedContext, id string) ([]Event, error) { + rows, err := r.queries.GetPatronRequestEvents(ctx, r.GetConnOrTx(), id) + var events []Event + if err == nil { + for _, r := range rows { + events = append(events, r.Event) + } + } + return events, err +} + func (r *PgEventRepo) DeleteEventsByIllTransaction(ctx common.ExtendedContext, illTransId string) error { return r.queries.DeleteEventsByIllTransaction(ctx, r.GetConnOrTx(), illTransId) } diff --git a/broker/oapi/open-api.yaml b/broker/oapi/open-api.yaml index d7e35341..4976a500 100644 --- a/broker/oapi/open-api.yaml +++ b/broker/oapi/open-api.yaml @@ -216,6 +216,9 @@ components: illTransactionID: type: string description: ID of the ILL transaction (if applicable) + patronRequestID: + type: string + description: ID of the Patron request (if applicable) eventType: type: string description: Type of the event @@ -1167,6 +1170,43 @@ paths: schema: $ref: '#/components/schemas/Error' + /patron_requests/{id}/events: + get: + summary: Retrieve patron request related events + parameters: + - in: path + name: id + schema: + type: string + required: true + description: ID of the patron request + - $ref: '#/components/parameters/Tenant' + - $ref: '#/components/parameters/Side' + - $ref: '#/components/parameters/Symbol' + tags: + - patron-requests-api + responses: + '200': + description: Successful retrieval of patron request events + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Event' + '400': + description: Bad Request. Invalid query parameters. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /sse/events: get: summary: Subscribe to real-time notifications. Notification is send out every time when ISO18626 message is sent out diff --git a/broker/patron_request/api/api-handler.go b/broker/patron_request/api/api-handler.go index 9891e347..c97e75d9 100644 --- a/broker/patron_request/api/api-handler.go +++ b/broker/patron_request/api/api-handler.go @@ -14,6 +14,7 @@ import ( "github.com/indexdata/crosslink/broker/api" "github.com/indexdata/crosslink/broker/common" "github.com/indexdata/crosslink/broker/events" + "github.com/indexdata/crosslink/broker/oapi" pr_db "github.com/indexdata/crosslink/broker/patron_request/db" "github.com/indexdata/crosslink/broker/patron_request/proapi" prservice "github.com/indexdata/crosslink/broker/patron_request/service" @@ -29,15 +30,18 @@ type PatronRequestApiHandler struct { limitDefault int32 prRepo pr_db.PrRepo eventBus events.EventBus + eventRepo events.EventRepo actionMappingService prservice.ActionMappingService tenant common.Tenant } -func NewPrApiHandler(prRepo pr_db.PrRepo, eventBus events.EventBus, tenant common.Tenant, limitDefault int32) PatronRequestApiHandler { +func NewPrApiHandler(prRepo pr_db.PrRepo, eventBus events.EventBus, + eventRepo events.EventRepo, tenant common.Tenant, limitDefault int32) PatronRequestApiHandler { return PatronRequestApiHandler{ limitDefault: limitDefault, prRepo: prRepo, eventBus: eventBus, + eventRepo: eventRepo, actionMappingService: prservice.ActionMappingService{}, tenant: tenant, } @@ -380,6 +384,40 @@ func (a *PatronRequestApiHandler) ConfirmActionProcess(ctx common.ExtendedContex } } +func (a *PatronRequestApiHandler) GetPatronRequestsIdEvents(w http.ResponseWriter, r *http.Request, id string, params proapi.GetPatronRequestsIdEventsParams) { + symbol, err := api.GetSymbolForRequest(r, a.tenant, params.XOkapiTenant, params.Symbol) + logParams := map[string]string{"method": "GetPatronRequestsIdEvents", "id": id, "symbol": symbol} + if params.Side != nil { + logParams["side"] = *params.Side + } + ctx := common.CreateExtCtxWithArgs(context.Background(), &common.LoggerArgs{Other: logParams}) + + if err != nil { + addBadRequestError(ctx, w, err) + return + } + pr, err := a.getPatronRequestById(ctx, id, params.Side, symbol) + if err != nil { + addInternalError(ctx, w, err) + return + } + if pr == nil { + addNotFoundError(w) + return + } + events, err := a.eventRepo.GetPatronRequestEvents(ctx, pr.ID) + if err != nil { + addInternalError(ctx, w, err) + return + } + + var responseItems []oapi.Event + for _, event := range events { + responseItems = append(responseItems, toApiEvent(event)) + } + writeJsonResponse(w, responseItems) +} + func writeJsonResponse(w http.ResponseWriter, resp any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -500,3 +538,20 @@ type RequestWait struct { w *http.ResponseWriter wg *sync.WaitGroup } + +func toApiEvent(event events.Event) oapi.Event { + api := oapi.Event{ + Id: event.ID, + Timestamp: event.Timestamp.Time, + PatronRequestID: &event.PatronRequestID, + EventType: string(event.EventType), + EventName: string(event.EventName), + EventStatus: string(event.EventStatus), + ParentID: toString(event.ParentID), + } + eventData := utils.Must(common.StructToMap(event.EventData)) + api.EventData = &eventData + resultData := utils.Must(common.StructToMap(event.ResultData)) + api.ResultData = &resultData + return api +} diff --git a/broker/patron_request/api/api-handler_test.go b/broker/patron_request/api/api-handler_test.go index 73feef9f..81e7b7c9 100644 --- a/broker/patron_request/api/api-handler_test.go +++ b/broker/patron_request/api/api-handler_test.go @@ -17,6 +17,7 @@ import ( pr_db "github.com/indexdata/crosslink/broker/patron_request/db" "github.com/indexdata/crosslink/broker/patron_request/proapi" prservice "github.com/indexdata/crosslink/broker/patron_request/service" + "github.com/indexdata/crosslink/broker/test/mocks" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" "github.com/stretchr/testify/assert" @@ -24,6 +25,7 @@ import ( ) var mockEventBus = new(MockEventBus) +var mockEventRepo = new(mocks.MockEventRepositorySuccess) var symbol = "ISIL:REQ" var lendingString = string(prservice.SideLending) var proapiBorrowingSide = proapi.Side(prservice.SideBorrowing) @@ -45,7 +47,7 @@ func TestGetDbText(t *testing.T) { } func TestGetPatronRequests(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() params := proapi.GetPatronRequestsParams{ @@ -58,7 +60,7 @@ func TestGetPatronRequests(t *testing.T) { } func TestGetPatronRequestsNoSymbol(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() params := proapi.GetPatronRequestsParams{ @@ -70,7 +72,7 @@ func TestGetPatronRequestsNoSymbol(t *testing.T) { } func TestGetPatronRequestsWithLimits(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() offset := proapi.Offset(10) @@ -89,7 +91,7 @@ func TestGetPatronRequestsWithLimits(t *testing.T) { } func TestPostPatronRequests(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) toCreate := proapi.PatronRequest{Id: "1", RequesterSymbol: &symbol} jsonBytes, err := json.Marshal(toCreate) assert.NoError(t, err, "failed to marshal patron request") @@ -103,7 +105,7 @@ func TestPostPatronRequests(t *testing.T) { } func TestPostPatronRequestsMissingSymbol(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) toCreate := proapi.PatronRequest{Id: "1"} jsonBytes, err := json.Marshal(toCreate) assert.NoError(t, err, "failed to marshal patron request") @@ -117,7 +119,7 @@ func TestPostPatronRequestsMissingSymbol(t *testing.T) { } func TestPostPatronRequestsInvalidJson(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", bytes.NewBuffer([]byte("a\": v\""))) rr := httptest.NewRecorder() tenant := proapi.Tenant("test-lib") @@ -127,7 +129,7 @@ func TestPostPatronRequestsInvalidJson(t *testing.T) { } func TestDeletePatronRequestsIdNotFound(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.DeletePatronRequestsId(rr, req, "2", proapi.DeletePatronRequestsIdParams{Symbol: &symbol}) @@ -135,7 +137,7 @@ func TestDeletePatronRequestsIdNotFound(t *testing.T) { } func TestDeletePatronRequestsIdMissingSymbol(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.DeletePatronRequestsId(rr, req, "2", proapi.DeletePatronRequestsIdParams{}) @@ -144,7 +146,7 @@ func TestDeletePatronRequestsIdMissingSymbol(t *testing.T) { } func TestDeletePatronRequestsIdError(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.DeletePatronRequestsId(rr, req, "1", proapi.DeletePatronRequestsIdParams{Symbol: &symbol}) @@ -153,7 +155,7 @@ func TestDeletePatronRequestsIdError(t *testing.T) { } func TestDeletePatronRequestsId(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.DeletePatronRequestsId(rr, req, "3", proapi.DeletePatronRequestsIdParams{Symbol: &symbol, Side: &proapiBorrowingSide}) @@ -162,7 +164,7 @@ func TestDeletePatronRequestsId(t *testing.T) { } func TestDeletePatronRequestsIdDeleted(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.DeletePatronRequestsId(rr, req, "4", proapi.DeletePatronRequestsIdParams{Symbol: &symbol, Side: &proapiBorrowingSide}) @@ -170,7 +172,7 @@ func TestDeletePatronRequestsIdDeleted(t *testing.T) { } func TestGetPatronRequestsIdMissingSymbol(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsId(rr, req, "2", proapi.GetPatronRequestsIdParams{}) @@ -179,7 +181,7 @@ func TestGetPatronRequestsIdMissingSymbol(t *testing.T) { } func TestGetPatronRequestsIdNotFound(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsId(rr, req, "2", proapi.GetPatronRequestsIdParams{Symbol: &symbol}) @@ -187,7 +189,7 @@ func TestGetPatronRequestsIdNotFound(t *testing.T) { } func TestGetPatronRequestsId(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("POST", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsId(rr, req, "1", proapi.GetPatronRequestsIdParams{Symbol: &symbol}) @@ -196,7 +198,7 @@ func TestGetPatronRequestsId(t *testing.T) { } func TestGetPatronRequestsIdActions(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsIdActions(rr, req, "3", proapi.GetPatronRequestsIdActionsParams{Symbol: &symbol, Side: &proapiBorrowingSide}) @@ -205,7 +207,7 @@ func TestGetPatronRequestsIdActions(t *testing.T) { } func TestGetPatronRequestsIdActionsNoSymbol(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsIdActions(rr, req, "3", proapi.GetPatronRequestsIdActionsParams{Side: &proapiBorrowingSide}) @@ -214,7 +216,7 @@ func TestGetPatronRequestsIdActionsNoSymbol(t *testing.T) { } func TestGetPatronRequestsIdActionsDbError(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsIdActions(rr, req, "1", proapi.GetPatronRequestsIdActionsParams{Symbol: &symbol, Side: &proapiBorrowingSide}) @@ -223,7 +225,7 @@ func TestGetPatronRequestsIdActionsDbError(t *testing.T) { } func TestGetPatronRequestsIdActionsNotFoundBecauseOfSide(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.GetPatronRequestsIdActions(rr, req, "3", proapi.GetPatronRequestsIdActionsParams{Symbol: &symbol, Side: &proapiLendingSide}) @@ -232,7 +234,7 @@ func TestGetPatronRequestsIdActionsNotFoundBecauseOfSide(t *testing.T) { } func TestPostPatronRequestsIdActionNoSymbol(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.PostPatronRequestsIdAction(rr, req, "3", proapi.PostPatronRequestsIdActionParams{Side: &proapiBorrowingSide}) @@ -241,7 +243,7 @@ func TestPostPatronRequestsIdActionNoSymbol(t *testing.T) { } func TestPostPatronRequestsIdActionDbError(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.PostPatronRequestsIdAction(rr, req, "1", proapi.PostPatronRequestsIdActionParams{Symbol: &symbol, Side: &proapiBorrowingSide}) @@ -250,7 +252,7 @@ func TestPostPatronRequestsIdActionDbError(t *testing.T) { } func TestPostPatronRequestsIdActionNotFoundBecauseOfSide(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", nil) rr := httptest.NewRecorder() handler.PostPatronRequestsIdAction(rr, req, "3", proapi.PostPatronRequestsIdActionParams{Symbol: &symbol, Side: &proapiLendingSide}) @@ -259,7 +261,7 @@ func TestPostPatronRequestsIdActionNotFoundBecauseOfSide(t *testing.T) { } func TestPostPatronRequestsIdActionErrorParsing(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) req, _ := http.NewRequest("GET", "/", strings.NewReader("{")) rr := httptest.NewRecorder() handler.PostPatronRequestsIdAction(rr, req, "3", proapi.PostPatronRequestsIdActionParams{Symbol: &symbol, Side: &proapiBorrowingSide}) @@ -267,8 +269,44 @@ func TestPostPatronRequestsIdActionErrorParsing(t *testing.T) { assert.Contains(t, rr.Body.String(), "unexpected EOF") } +func TestGetPatronRequestsIdEventsNoSymbol(t *testing.T) { + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) + req, _ := http.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + handler.GetPatronRequestsIdEvents(rr, req, "3", proapi.GetPatronRequestsIdEventsParams{Side: &proapiBorrowingSide}) + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.Contains(t, rr.Body.String(), "symbol must be specified") +} + +func TestGetPatronRequestsIdEventsDbError(t *testing.T) { + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) + req, _ := http.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + handler.GetPatronRequestsIdEvents(rr, req, "1", proapi.GetPatronRequestsIdEventsParams{Symbol: &symbol, Side: &proapiBorrowingSide}) + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.Contains(t, rr.Body.String(), "DB error") +} + +func TestGetPatronRequestsIdEventsNotFoundBecauseOfSide(t *testing.T) { + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) + req, _ := http.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + handler.GetPatronRequestsIdEvents(rr, req, "3", proapi.GetPatronRequestsIdEventsParams{Symbol: &symbol, Side: &proapiLendingSide}) + assert.Equal(t, http.StatusNotFound, rr.Code) + assert.Contains(t, rr.Body.String(), "not found") +} + +func TestGetPatronRequestsIdEventsErrorGettingEvents(t *testing.T) { + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, new(mocks.MockEventRepositoryError), common.NewTenant(""), 10) + req, _ := http.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + handler.GetPatronRequestsIdEvents(rr, req, "3", proapi.GetPatronRequestsIdEventsParams{Symbol: &symbol, Side: &proapiBorrowingSide}) + assert.Equal(t, http.StatusInternalServerError, rr.Code) + assert.Contains(t, rr.Body.String(), "DB error") +} + func TestToDbPatronRequest(t *testing.T) { - handler := NewPrApiHandler(new(PrRepoError), mockEventBus, common.NewTenant(""), 10) + handler := NewPrApiHandler(new(PrRepoError), mockEventBus, mockEventRepo, common.NewTenant(""), 10) ctx := common.CreateExtCtxWithArgs(context.Background(), &common.LoggerArgs{}) id := uuid.NewString() diff --git a/broker/sqlc/event_query.sql b/broker/sqlc/event_query.sql index d7791006..85ca63cd 100644 --- a/broker/sqlc/event_query.sql +++ b/broker/sqlc/event_query.sql @@ -40,6 +40,12 @@ FROM event WHERE ill_transaction_id = $1 ORDER BY timestamp; +-- name: GetPatronRequestEvents :many +SELECT sqlc.embed(event) +FROM event +WHERE patron_request_id = $1 +ORDER BY timestamp; + -- name: SaveEvent :one INSERT INTO event ( id, timestamp, ill_transaction_id, parent_id, event_type, event_name, event_status, event_data, result_data, last_signal, broadcast, patron_request_id diff --git a/broker/test/mocks/mock_eventrepo.go b/broker/test/mocks/mock_eventrepo.go index 0766ed49..c44cf9a3 100644 --- a/broker/test/mocks/mock_eventrepo.go +++ b/broker/test/mocks/mock_eventrepo.go @@ -88,6 +88,13 @@ func (r *MockEventRepositorySuccess) GetLatestRequestEventByAction(ctx common.Ex }, nil } +func (r *MockEventRepositorySuccess) GetPatronRequestEvents(ctx common.ExtendedContext, id string) ([]events.Event, error) { + return []events.Event{{ + ID: uuid.New().String(), + PatronRequestID: id, + }}, nil +} + type MockEventRepositoryError struct { mock.Mock } @@ -131,3 +138,7 @@ func (r *MockEventRepositoryError) DeleteEventsByIllTransaction(ctx common.Exten func (r *MockEventRepositoryError) GetLatestRequestEventByAction(ctx common.ExtendedContext, illTransId string, action string) (events.Event, error) { return events.Event{}, errors.New("DB error") } + +func (r *MockEventRepositoryError) GetPatronRequestEvents(ctx common.ExtendedContext, id string) ([]events.Event, error) { + return []events.Event{}, errors.New("DB error") +} diff --git a/broker/test/patron_request/api/api-handler_test.go b/broker/test/patron_request/api/api-handler_test.go index 4e24e212..9b5d754c 100644 --- a/broker/test/patron_request/api/api-handler_test.go +++ b/broker/test/patron_request/api/api-handler_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/indexdata/crosslink/broker/common" + "github.com/indexdata/crosslink/broker/oapi" pr_db "github.com/indexdata/crosslink/broker/patron_request/db" "github.com/indexdata/crosslink/broker/patron_request/proapi" "github.com/indexdata/crosslink/directory" @@ -375,12 +376,25 @@ func TestActionsToCompleteState(t *testing.T) { assert.NoError(t, err, "failed to unmarshal patron request") assert.Equal(t, string(prservice.BorrowerStateCompleted), foundPr.State) + // Check requester patron request event count + respBytes = httpRequest(t, "GET", requesterPrPath+"/events"+queryParams, []byte{}, 200) + var events []oapi.Event + err = json.Unmarshal(respBytes, &events) + assert.NoError(t, err, "failed to unmarshal patron request events") + assert.True(t, len(events) > 5) + // Check supplier patron request done respBytes = httpRequest(t, "GET", supplierPrPath+supQueryParams, []byte{}, 200) err = json.Unmarshal(respBytes, &foundPr) assert.NoError(t, err, "failed to unmarshal patron request") assert.Equal(t, supPr.ID, foundPr.Id) assert.Equal(t, string(prservice.LenderStateCompleted), foundPr.State) + + // Check supplier patron request event count + respBytes = httpRequest(t, "GET", supplierPrPath+"/events"+supQueryParams, []byte{}, 200) + err = json.Unmarshal(respBytes, &events) + assert.NoError(t, err, "failed to unmarshal patron request events") + assert.True(t, len(events) > 5) } func TestGetReturnableStateModel(t *testing.T) { From fb0f0699326137724ac0fb1c933c4ac75cd04f34 Mon Sep 17 00:00:00 2001 From: Janis Saldabols Date: Fri, 13 Feb 2026 15:24:37 +0200 Subject: [PATCH 2/2] ILLDEV-277 Remove code duplication --- broker/api/api-handler.go | 7 ++++--- broker/patron_request/api/api-handler.go | 19 +------------------ 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/broker/api/api-handler.go b/broker/api/api-handler.go index 34998d6e..11b078f2 100644 --- a/broker/api/api-handler.go +++ b/broker/api/api-handler.go @@ -136,7 +136,7 @@ func (a *ApiHandler) GetEvents(w http.ResponseWriter, r *http.Request, params oa } resp.About.Count = fullCount for _, event := range eventList { - resp.Items = append(resp.Items, toApiEvent(event)) + resp.Items = append(resp.Items, ToApiEvent(event, event.IllTransactionID, nil)) } writeJsonResponse(w, resp) } @@ -666,15 +666,16 @@ func addNotFoundError(w http.ResponseWriter) { _ = json.NewEncoder(w).Encode(resp) } -func toApiEvent(event events.Event) oapi.Event { +func ToApiEvent(event events.Event, illId string, prId *string) oapi.Event { api := oapi.Event{ Id: event.ID, Timestamp: event.Timestamp.Time, - IllTransactionID: event.IllTransactionID, + IllTransactionID: illId, EventType: string(event.EventType), EventName: string(event.EventName), EventStatus: string(event.EventStatus), ParentID: toString(event.ParentID), + PatronRequestID: prId, } eventData := utils.Must(common.StructToMap(event.EventData)) api.EventData = &eventData diff --git a/broker/patron_request/api/api-handler.go b/broker/patron_request/api/api-handler.go index c97e75d9..b1060956 100644 --- a/broker/patron_request/api/api-handler.go +++ b/broker/patron_request/api/api-handler.go @@ -413,7 +413,7 @@ func (a *PatronRequestApiHandler) GetPatronRequestsIdEvents(w http.ResponseWrite var responseItems []oapi.Event for _, event := range events { - responseItems = append(responseItems, toApiEvent(event)) + responseItems = append(responseItems, api.ToApiEvent(event, "", &event.PatronRequestID)) } writeJsonResponse(w, responseItems) } @@ -538,20 +538,3 @@ type RequestWait struct { w *http.ResponseWriter wg *sync.WaitGroup } - -func toApiEvent(event events.Event) oapi.Event { - api := oapi.Event{ - Id: event.ID, - Timestamp: event.Timestamp.Time, - PatronRequestID: &event.PatronRequestID, - EventType: string(event.EventType), - EventName: string(event.EventName), - EventStatus: string(event.EventStatus), - ParentID: toString(event.ParentID), - } - eventData := utils.Must(common.StructToMap(event.EventData)) - api.EventData = &eventData - resultData := utils.Must(common.StructToMap(event.ResultData)) - api.ResultData = &resultData - return api -}