Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion broker/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
github.com/dustin/go-humanize v1.0.1
github.com/golang-migrate/migrate/v4 v4.19.1
github.com/google/uuid v1.6.0
github.com/indexdata/cql-go v1.0.1-0.20250722084932-84f3837d6030
github.com/indexdata/cql-go v1.0.1-0.20260202173855-d9fe780396b2
github.com/indexdata/go-utils v0.0.0-20250210100229-d30dbd51df72
github.com/indexdata/xsd2goxsl v1.3.0
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438
Expand Down
2 changes: 2 additions & 0 deletions broker/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DW
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/indexdata/cql-go v1.0.1-0.20250722084932-84f3837d6030 h1:RP9TZZTGoBo2Jx04FEWaRmNhCX/Fk8VR04tX0FMRzik=
github.com/indexdata/cql-go v1.0.1-0.20250722084932-84f3837d6030/go.mod h1:zmSHcE8JyK94EWZrV7VyjLr2QfRoj+EeEOttl9wm64U=
github.com/indexdata/cql-go v1.0.1-0.20260202173855-d9fe780396b2 h1:HYBpSNIr26sFXyOfq4pMGk13ygEezb1UA4gtrt9lsm0=
github.com/indexdata/cql-go v1.0.1-0.20260202173855-d9fe780396b2/go.mod h1:zmSHcE8JyK94EWZrV7VyjLr2QfRoj+EeEOttl9wm64U=
github.com/indexdata/go-utils v0.0.0-20250210100229-d30dbd51df72 h1:/ssOlpKK1EOeWMCOUrxCOCZP+0Z1LD58Xg1nrU01TAQ=
github.com/indexdata/go-utils v0.0.0-20250210100229-d30dbd51df72/go.mod h1:0sW6Szxv8GNU3LBtK6mgBKDEUnlovPfghiG9xi+i0R8=
github.com/indexdata/xsd2goxsl v1.3.0 h1:LZGBORHnO6olHBtvc6hQEefymdRuiM77FgtW4pCek7g=
Expand Down
1 change: 0 additions & 1 deletion broker/oapi/open-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1084,4 +1084,3 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/SseResult'

86 changes: 67 additions & 19 deletions broker/patron_request/api/api-handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/indexdata/cql-go/cqlbuilder"
"github.com/indexdata/crosslink/broker/api"
"github.com/indexdata/crosslink/broker/common"
"github.com/indexdata/crosslink/broker/events"
Expand Down Expand Up @@ -60,9 +61,38 @@ func (a *PatronRequestApiHandler) GetPatronRequests(w http.ResponseWriter, r *ht
if params.Offset != nil {
offset = *params.Offset
}

updatedCql := addAccessRestrictions(params.Cql, params.Side, symbol)
prs, count, err := a.prRepo.ListPatronRequests(ctx, pr_db.ListPatronRequestsParams{Limit: limit, Offset: offset}, &updatedCql)
var qb *cqlbuilder.QueryBuilder
if params.Cql == nil {
qb = cqlbuilder.NewQuery()
qb.Search("cql.allRecords").Term("1")
} else {
qb, err = cqlbuilder.NewQueryFromString(*params.Cql)
if err != nil {
addBadRequestError(ctx, w, err)
return
}
}
var side pr_db.PatronRequestSide
if isSideParamValid(params.Side) {
side = pr_db.PatronRequestSide(params.Side)
_, err = qb.And().Search("side").Term(params.Side).Build()
if err != nil {
addBadRequestError(ctx, w, err)
return
}
}
qb, err = addOwnerRestriction(qb, symbol, side)
if err != nil {
addBadRequestError(ctx, w, err)
return
}
cql, err := qb.Build()
if err != nil {
addBadRequestError(ctx, w, err)
return
}
cqlStr := cql.String()
prs, count, err := a.prRepo.ListPatronRequests(ctx, pr_db.ListPatronRequestsParams{Limit: limit, Offset: offset}, &cqlStr)
if err != nil && !errors.Is(err, pgx.ErrNoRows) { //DB error
addInternalError(ctx, w, err)
return
Expand All @@ -87,18 +117,32 @@ func (a *PatronRequestApiHandler) GetPatronRequests(w http.ResponseWriter, r *ht
writeJsonResponse(w, resp)
}

func addAccessRestrictions(cql *string, side string, symbol string) string {
var restrict string
if side == string(prservice.SideLending) {
restrict = "side = " + string(prservice.SideLending) + " AND supplier_symbol = " + symbol
} else {
restrict = "side = " + string(prservice.SideBorrowing) + " AND requester_symbol = " + symbol
}
if cql == nil {
return restrict
} else {
return *cql + " AND " + restrict
}
func addOwnerRestriction(queryBuilder *cqlbuilder.QueryBuilder, symbol string, side pr_db.PatronRequestSide) (*cqlbuilder.QueryBuilder, error) {
var err error
switch side {
case prservice.SideLending:
_, err = queryBuilder.And().
Search("side").Term(string(prservice.SideLending)).
And().Search("supplier_symbol").Term(symbol).
Build()
case prservice.SideBorrowing:
_, err = queryBuilder.And().
Search("side").Term(string(prservice.SideBorrowing)).
And().Search("requester_symbol").Term(symbol).
Build()
default:
_, err = queryBuilder.And().
BeginClause().
Search("side").Term(string(prservice.SideLending)).
And().Search("supplier_symbol").Term(symbol).
EndClause().
Or().
BeginClause().Search("side").Term(string(prservice.SideBorrowing)).
And().Search("requester_symbol").Term(symbol).
EndClause().
Build()
}
return queryBuilder, err
}

func (a *PatronRequestApiHandler) PostPatronRequests(w http.ResponseWriter, r *http.Request, params proapi.PostPatronRequestsParams) {
Expand Down Expand Up @@ -185,15 +229,19 @@ func (a *PatronRequestApiHandler) getPatronRequestById(ctx common.ExtendedContex
}
return nil, err
}
if isOwner(pr, side, symbol) {
if isOwner(pr, symbol) && (!isSideParamValid(side) || string(pr.Side) == side) {
return &pr, nil
}
return nil, nil
}

func isOwner(pr pr_db.PatronRequest, side string, symbol string) bool {
return string(pr.Side) == side && ((side == string(prservice.SideBorrowing) && pr.RequesterSymbol.String == symbol) ||
(side == string(prservice.SideLending) && pr.SupplierSymbol.String == symbol))
func isSideParamValid(side string) bool {
return side == string(prservice.SideBorrowing) || side == string(prservice.SideLending)
}

func isOwner(pr pr_db.PatronRequest, symbol string) bool {
return (string(pr.Side) == string(prservice.SideBorrowing) && pr.RequesterSymbol.String == symbol) ||
(string(pr.Side) == string(prservice.SideLending) && pr.SupplierSymbol.String == symbol)
}

func (a *PatronRequestApiHandler) GetPatronRequestsId(w http.ResponseWriter, r *http.Request, id string, params proapi.GetPatronRequestsIdParams) {
Expand Down
12 changes: 12 additions & 0 deletions broker/patron_request/db/prcql.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,21 @@ import (
"github.com/indexdata/cql-go/pgcql"
)

type FieldAllRecords struct{}

func (f *FieldAllRecords) GetColumn() string { return "" }
func (f *FieldAllRecords) SetColumn(column string) {}
func (f *FieldAllRecords) Generate(sc cql.SearchClause, queryArgumentIndex int) (string, []any, error) {
// Accept standard cql.allRecords = 1 (ignore term/relation).
return "TRUE", nil, nil
}

func handlePatronRequestsQuery(cqlString string, noBaseArgs int) (pgcql.Query, error) {
def := pgcql.NewPgDefinition()

fa := &FieldAllRecords{}
def.AddField("cql.allRecords", fa)

f := pgcql.NewFieldString().WithExact()
def.AddField("state", f)

Expand Down
Loading