Skip to content

Commit

Permalink
fix(backend): return empty methods for complete or expired incomingPa…
Browse files Browse the repository at this point in the history
…yment
  • Loading branch information
BlairCurrey committed Oct 20, 2023
1 parent e68b48e commit 718d962
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 81 deletions.
50 changes: 46 additions & 4 deletions packages/backend/src/open_payments/payment/incoming/model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { truncateTables } from '../../../tests/tableManager'
import { IlpStreamCredentials } from '../../../payment-method/ilp/stream-credentials/service'
import { serializeAmount } from '../../amount'
import { IlpAddress } from 'ilp-packet'
import { IncomingPayment } from './model'
import { IncomingPayment, IncomingPaymentState } from './model'

describe('Incoming Payment Model', (): void => {
let deps: IocContract<AppServices>
Expand All @@ -30,7 +30,7 @@ describe('Incoming Payment Model', (): void => {
})

describe('toOpenPaymentsType', () => {
test('returns incoming payment without stream credentials provided', async () => {
test('returns incoming payment', async () => {
const walletAddress = await createWalletAddress(deps)
const incomingPayment = await createIncomingPayment(deps, {
walletAddressId: walletAddress.id,
Expand All @@ -51,8 +51,10 @@ describe('Incoming Payment Model', (): void => {
createdAt: incomingPayment.createdAt.toISOString()
})
})
})

test('returns incoming payment with stream credentials as object', async () => {
describe('toOpenPaymentsTypeWithMethods', () => {
test('returns incoming payment with payment methods', async () => {
const walletAddress = await createWalletAddress(deps)
const incomingPayment = await createIncomingPayment(deps, {
walletAddressId: walletAddress.id,
Expand All @@ -65,7 +67,10 @@ describe('Incoming Payment Model', (): void => {
}

expect(
incomingPayment.toOpenPaymentsType(walletAddress, streamCredentials)
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)
).toEqual({
id: `${walletAddress.url}${IncomingPayment.urlPath}/${incomingPayment.id}`,
walletAddress: walletAddress.url,
Expand All @@ -87,5 +92,42 @@ describe('Incoming Payment Model', (): void => {
]
})
})

test.each([IncomingPaymentState.Completed, IncomingPaymentState.Expired])(
'returns incoming payment with empty methods if payment state is %s',
async (paymentState): Promise<void> => {
const walletAddress = await createWalletAddress(deps)
const incomingPayment = await createIncomingPayment(deps, {
walletAddressId: walletAddress.id,
metadata: { description: 'my payment' }
})
incomingPayment.state = paymentState

const streamCredentials: IlpStreamCredentials = {
ilpAddress: 'test.ilp' as IlpAddress,
sharedSecret: Buffer.from('')
}

expect(
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)
).toEqual({
id: `${walletAddress.url}${IncomingPayment.urlPath}/${incomingPayment.id}`,
walletAddress: walletAddress.url,
completed: incomingPayment.completed,
receivedAmount: serializeAmount(incomingPayment.receivedAmount),
incomingAmount: incomingPayment.incomingAmount
? serializeAmount(incomingPayment.incomingAmount)
: undefined,
expiresAt: incomingPayment.expiresAt.toISOString(),
metadata: incomingPayment.metadata ?? undefined,
updatedAt: incomingPayment.updatedAt.toISOString(),
createdAt: incomingPayment.createdAt.toISOString(),
methods: []
})
}
)
})
})
48 changes: 18 additions & 30 deletions packages/backend/src/open_payments/payment/incoming/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,23 +200,8 @@ export class IncomingPayment

public toOpenPaymentsType(
walletAddress: WalletAddress
): OpenPaymentsIncomingPayment
public toOpenPaymentsType(
walletAddress: WalletAddress,
ilpStreamCredentials: IlpStreamCredentials
): OpenPaymentsIncomingPaymentWithPaymentMethod
public toOpenPaymentsType(
walletAddress: WalletAddress,
ilpStreamCredentials?: IlpStreamCredentials
): OpenPaymentsIncomingPayment | OpenPaymentsIncomingPaymentWithPaymentMethod

public toOpenPaymentsType(
walletAddress: WalletAddress,
ilpStreamCredentials?: IlpStreamCredentials
):
| OpenPaymentsIncomingPayment
| OpenPaymentsIncomingPaymentWithPaymentMethod {
const baseIncomingPayment: OpenPaymentsIncomingPayment = {
): OpenPaymentsIncomingPayment {
return {
id: this.getUrl(walletAddress),
walletAddress: walletAddress.url,
incomingAmount: this.incomingAmount
Expand All @@ -229,21 +214,24 @@ export class IncomingPayment
updatedAt: this.updatedAt.toISOString(),
expiresAt: this.expiresAt.toISOString()
}
}

if (ilpStreamCredentials) {
return {
...baseIncomingPayment,
methods: [
{
type: 'ilp',
ilpAddress: ilpStreamCredentials.ilpAddress,
sharedSecret: base64url(ilpStreamCredentials.sharedSecret)
}
]
}
public toOpenPaymentsTypeWithMethods(
walletAddress: WalletAddress,
ilpStreamCredentials: IlpStreamCredentials
): OpenPaymentsIncomingPaymentWithPaymentMethod {
return {
...this.toOpenPaymentsType(walletAddress),
methods: this.isExpiredOrComplete()
? []
: [
{
type: 'ilp',
ilpAddress: ilpStreamCredentials.ilpAddress,
sharedSecret: base64url(ilpStreamCredentials.sharedSecret)
}
]
}

return baseIncomingPayment
}

public toPublicOpenPaymentsType(): Pick<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
ListContext
} from '../../../app'
import { truncateTables } from '../../../tests/tableManager'
import { IncomingPayment } from './model'
import { IncomingPayment, IncomingPaymentState } from './model'
import {
IncomingPaymentRoutes,
CreateBody,
Expand Down Expand Up @@ -143,6 +143,36 @@ describe('Incoming Payment Routes', (): void => {
})
})

describe('get', (): void => {
test.each([IncomingPaymentState.Completed, IncomingPaymentState.Expired])(
'returns incoming payment with empty methods if payment state is %s',
async (paymentState): Promise<void> => {
const walletAddress = await createWalletAddress(deps)
const incomingPayment = await createIncomingPayment(deps, {
walletAddressId: walletAddress.id
})
await incomingPayment.$query().update({ state: paymentState })

const ctx = setup<ReadContextWithAuthenticatedStatus>({
reqOpts: {
headers: { Accept: 'application/json' },
method: 'GET',
url: `/incoming-payments/${incomingPayment.id}`
},
params: {
id: incomingPayment.id
},
walletAddress
})

await expect(incomingPaymentRoutes.get(ctx)).resolves.toBeUndefined()

expect(ctx.response).toSatisfyApiSpec()
expect(ctx.body).toMatchObject({ methods: [] })
}
)
})

describe('create', (): void => {
let amount: AmountJSON

Expand Down
32 changes: 7 additions & 25 deletions packages/backend/src/open_payments/payment/incoming/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,8 @@ import {
} from './errors'
import { AmountJSON, parseAmount } from '../../amount'
import { listSubresource } from '../../wallet_address/routes'
import {
IlpStreamCredentials,
StreamCredentialsService
} from '../../../payment-method/ilp/stream-credentials/service'
import {
AccessAction,
IncomingPayment as OpenPaymentsIncomingPayment,
IncomingPaymentWithPaymentMethods
} from '@interledger/open-payments'
import { WalletAddress } from '../../wallet_address/model'
import { StreamCredentialsService } from '../../../payment-method/ilp/stream-credentials/service'
import { AccessAction } from '@interledger/open-payments'

interface ServiceDependencies {
config: IAppConfig
Expand Down Expand Up @@ -110,9 +102,8 @@ async function getIncomingPaymentPrivate(

const streamCredentials = deps.streamCredentialsService.get(incomingPayment)

ctx.body = incomingPaymentToBody(
ctx.body = incomingPayment.toOpenPaymentsTypeWithMethods(
incomingPayment.walletAddress,
incomingPayment,
streamCredentials
)
}
Expand Down Expand Up @@ -158,9 +149,8 @@ async function createIncomingPayment(
const streamCredentials = deps.streamCredentialsService.get(
incomingPaymentOrError
)
ctx.body = incomingPaymentToBody(
ctx.body = incomingPaymentOrError.toOpenPaymentsTypeWithMethods(
incomingPaymentOrError.walletAddress,
incomingPaymentOrError,
streamCredentials
)
}
Expand Down Expand Up @@ -189,9 +179,8 @@ async function completeIncomingPayment(
ctx.throw(404)
}

ctx.body = incomingPaymentToBody(
incomingPaymentOrError.walletAddress,
incomingPaymentOrError
ctx.body = incomingPaymentOrError.toOpenPaymentsType(
incomingPaymentOrError.walletAddress
)
}

Expand All @@ -203,7 +192,7 @@ async function listIncomingPayments(
await listSubresource({
ctx,
getWalletAddressPage: deps.incomingPaymentService.getWalletAddressPage,
toBody: (payment) => incomingPaymentToBody(ctx.walletAddress, payment)
toBody: (payment) => payment.toOpenPaymentsType(ctx.walletAddress)
})
} catch (err) {
if (err instanceof Koa.HttpError) {
Expand All @@ -212,10 +201,3 @@ async function listIncomingPayments(
ctx.throw(500, 'Error trying to list incoming payments')
}
}
function incomingPaymentToBody(
walletAddress: WalletAddress,
incomingPayment: IncomingPayment,
ilpStreamCredentials?: IlpStreamCredentials
): OpenPaymentsIncomingPayment | IncomingPaymentWithPaymentMethods {
return incomingPayment.toOpenPaymentsType(walletAddress, ilpStreamCredentials)
}
32 changes: 19 additions & 13 deletions packages/backend/src/open_payments/receiver/model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ describe('Receiver Model', (): void => {
assert(streamCredentials)

const receiver = new Receiver(
incomingPayment.toOpenPaymentsType(walletAddress, streamCredentials)
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)
)

expect(receiver).toEqual({
Expand Down Expand Up @@ -87,10 +90,11 @@ describe('Receiver Model', (): void => {
sharedSecret: Buffer.from('')
}

const openPaymentsIncomingPayment = incomingPayment.toOpenPaymentsType(
walletAddress,
streamCredentials
)
const openPaymentsIncomingPayment =
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)

expect(() => new Receiver(openPaymentsIncomingPayment)).toThrow(
'Cannot create receiver from completed incoming payment'
Expand All @@ -106,10 +110,11 @@ describe('Receiver Model', (): void => {
incomingPayment.expiresAt = new Date(Date.now() - 1)
const streamCredentials = streamCredentialsService.get(incomingPayment)
assert(streamCredentials)
const openPaymentsIncomingPayment = incomingPayment.toOpenPaymentsType(
walletAddress,
streamCredentials
)
const openPaymentsIncomingPayment =
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)

expect(() => new Receiver(openPaymentsIncomingPayment)).toThrow(
'Cannot create receiver from expired incoming payment'
Expand All @@ -126,10 +131,11 @@ describe('Receiver Model', (): void => {
assert(streamCredentials)
;(streamCredentials.ilpAddress as string) = 'not base 64 encoded'

const openPaymentsIncomingPayment = incomingPayment.toOpenPaymentsType(
walletAddress,
streamCredentials
)
const openPaymentsIncomingPayment =
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)

expect(() => new Receiver(openPaymentsIncomingPayment)).toThrow(
'Invalid ILP address on ilp payment method'
Expand Down
8 changes: 4 additions & 4 deletions packages/backend/src/open_payments/receiver/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ export class Receiver {
public readonly incomingPayment: ReceiverIncomingPayment

constructor(incomingPayment: OpenPaymentsIncomingPaymentWithPaymentMethod) {
if (!incomingPayment.methods.length) {
throw new Error('Missing payment method(s) on incoming payment')
}

if (incomingPayment.completed) {
throw new Error('Cannot create receiver from completed incoming payment')
}

if (!incomingPayment.methods.length) {
throw new Error('Missing payment method(s) on incoming payment')
}

const expiresAt = incomingPayment.expiresAt
? new Date(incomingPayment.expiresAt)
: undefined
Expand Down
7 changes: 5 additions & 2 deletions packages/backend/src/open_payments/receiver/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ async function createLocalIncomingPayment(
incomingPaymentOrError
)

return incomingPaymentOrError.toOpenPaymentsType(
return incomingPaymentOrError.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)
Expand Down Expand Up @@ -227,7 +227,10 @@ async function getLocalIncomingPayment({

const streamCredentials = deps.streamCredentialsService.get(incomingPayment)

return incomingPayment.toOpenPaymentsType(walletAddress, streamCredentials)
return incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)
}

async function getIncomingPaymentGrant(
Expand Down
5 changes: 4 additions & 1 deletion packages/backend/src/tests/outgoingPayment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ export async function createOutgoingPayment(
.spyOn(receiverService, 'get')
.mockResolvedValueOnce(
new Receiver(
incomingPayment.toOpenPaymentsType(walletAddress, streamCredentials)
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentials
)
)
)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/tests/receiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export async function createReceiver(
const streamCredentialsService = await deps.use('streamCredentialsService')

return new Receiver(
incomingPayment.toOpenPaymentsType(
incomingPayment.toOpenPaymentsTypeWithMethods(
walletAddress,
streamCredentialsService.get(incomingPayment)!
)
Expand Down

0 comments on commit 718d962

Please sign in to comment.