diff --git a/localenv/mock-account-servicing-entity/app/lib/asset.server.ts b/localenv/mock-account-servicing-entity/app/lib/asset.server.ts index 0f97f636ea..e887c182db 100644 --- a/localenv/mock-account-servicing-entity/app/lib/asset.server.ts +++ b/localenv/mock-account-servicing-entity/app/lib/asset.server.ts @@ -31,6 +31,10 @@ export const listAssets = async ( withdrawalThreshold tenantId createdAt + tenant { + id + publicName + } } } pageInfo { diff --git a/localenv/mock-account-servicing-entity/generated/graphql.ts b/localenv/mock-account-servicing-entity/generated/graphql.ts index 35e0959e56..e3b7f1e8aa 100644 --- a/localenv/mock-account-servicing-entity/generated/graphql.ts +++ b/localenv/mock-account-servicing-entity/generated/graphql.ts @@ -124,7 +124,8 @@ export type Asset = Model & { scale: Scalars['UInt8']['output']; /** The sending fee structure for the asset. */ sendingFee?: Maybe; - tenantId: Scalars['ID']['output']; + /** The tenant that the asset belongs to. */ + tenant?: Maybe; /** Minimum amount of liquidity that can be withdrawn from the asset. */ withdrawalThreshold?: Maybe; }; @@ -618,8 +619,8 @@ export type IncomingPayment = BasePayment & Model & { receivedAmount: Amount; /** State of the incoming payment. */ state: IncomingPaymentState; - /** The tenant UUID associated with the incoming payment. If not provided, it will be obtained from the signature. */ - tenantId?: Maybe; + /** The tenant associated with the incoming payment. If not provided, it will be obtained from the signature. */ + tenant?: Maybe; /** Unique identifier of the wallet address under which the incoming payment was created. */ walletAddressId: Scalars['ID']['output']; }; @@ -1034,8 +1035,8 @@ export type OutgoingPayment = BasePayment & Model & { state: OutgoingPaymentState; /** Number of attempts made to send an outgoing payment. */ stateAttempts: Scalars['Int']['output']; - /** Tenant ID of the outgoing payment. */ - tenantId?: Maybe; + /** Tenant of the outgoing payment. */ + tenant?: Maybe; /** Unique identifier of the wallet address under which the outgoing payment was created. */ walletAddressId: Scalars['ID']['output']; }; @@ -1110,6 +1111,8 @@ export type Payment = BasePayment & Model & { metadata?: Maybe; /** State of the payment, either `IncomingPaymentState` or `OutgoingPaymentState` according to payment type */ state: Scalars['String']['output']; + /** The tenant associated with the payment. */ + tenant?: Maybe; /** Type of payment, either incoming or outgoing. */ type: PaymentType; /** Unique identifier of the wallet address under which the payment was created. */ @@ -1167,7 +1170,7 @@ export type Peer = Model & { /** ILP address of the peer. */ staticIlpAddress: Scalars['String']['output']; /** Unique identifier of the tenant associated with the peer. */ - tenantId: Scalars['ID']['output']; + tenant?: Maybe; }; export type PeerEdge = { @@ -1668,8 +1671,8 @@ export type WalletAddress = Model & { quotes?: Maybe; /** The current status of the wallet, either active or inactive. */ status: WalletAddressStatus; - /** Tenant ID of the wallet address. */ - tenantId?: Maybe; + /** Tenant of the wallet address. */ + tenant?: Maybe; /** List of keys associated with this wallet address */ walletAddressKeys?: Maybe; }; @@ -1788,7 +1791,7 @@ export type WebhookEvent = Model & { /** Unique identifier of the webhook event. */ id: Scalars['ID']['output']; /** Tenant of the webhook event. */ - tenantId: Scalars['ID']['output']; + tenant?: Maybe; /** Type of webhook event. */ type: Scalars['String']['output']; }; @@ -2227,7 +2230,7 @@ export type AssetResolvers, ParentType, ContextType>; scale?: Resolver; sendingFee?: Resolver, ParentType, ContextType>; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; withdrawalThreshold?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2351,7 +2354,7 @@ export type IncomingPaymentResolvers, ParentType, ContextType>; receivedAmount?: Resolver; state?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2453,7 +2456,7 @@ export type OutgoingPaymentResolvers; state?: Resolver; stateAttempts?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2490,6 +2493,7 @@ export type PaymentResolvers, ParentType, ContextType>; metadata?: Resolver, ParentType, ContextType>; state?: Resolver; + tenant?: Resolver, ParentType, ContextType>; type?: Resolver; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -2517,7 +2521,7 @@ export type PeerResolvers, ParentType, ContextType>; name?: Resolver, ParentType, ContextType>; staticIlpAddress?: Resolver; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2679,7 +2683,7 @@ export type WalletAddressResolvers, ParentType, ContextType>; quotes?: Resolver, ParentType, ContextType, Partial>; status?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressKeys?: Resolver, ParentType, ContextType, Partial>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2733,7 +2737,7 @@ export type WebhookEventResolvers; data?: Resolver; id?: Resolver; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; type?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; diff --git a/packages/backend/src/graphql/generated/graphql.schema.json b/packages/backend/src/graphql/generated/graphql.schema.json index b1a2237a96..91ef1cbb70 100644 --- a/packages/backend/src/graphql/generated/graphql.schema.json +++ b/packages/backend/src/graphql/generated/graphql.schema.json @@ -730,17 +730,13 @@ "deprecationReason": null }, { - "name": "tenantId", - "description": null, + "name": "tenant", + "description": "The tenant that the asset belongs to.", "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } + "kind": "OBJECT", + "name": "Tenant", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -3709,12 +3705,12 @@ "deprecationReason": null }, { - "name": "tenantId", - "description": "The tenant UUID associated with the incoming payment. If not provided, it will be obtained from the signature.", + "name": "tenant", + "description": "The tenant associated with the incoming payment. If not provided, it will be obtained from the signature.", "args": [], "type": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Tenant", "ofType": null }, "isDeprecated": false, @@ -5758,12 +5754,12 @@ "deprecationReason": null }, { - "name": "tenantId", - "description": "Tenant ID of the outgoing payment.", + "name": "tenant", + "description": "Tenant of the outgoing payment.", "args": [], "type": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Tenant", "ofType": null }, "isDeprecated": false, @@ -6170,6 +6166,18 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "tenant", + "description": "The tenant associated with the payment.", + "args": [], + "type": { + "kind": "OBJECT", + "name": "Tenant", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "type", "description": "Type of payment, either incoming or outgoing.", @@ -6510,17 +6518,13 @@ "deprecationReason": null }, { - "name": "tenantId", + "name": "tenant", "description": "Unique identifier of the tenant associated with the peer.", "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } + "kind": "OBJECT", + "name": "Tenant", + "ofType": null }, "isDeprecated": false, "deprecationReason": null @@ -9673,12 +9677,12 @@ "deprecationReason": null }, { - "name": "tenantId", - "description": "Tenant ID of the wallet address.", + "name": "tenant", + "description": "Tenant of the wallet address.", "args": [], "type": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Tenant", "ofType": null }, "isDeprecated": false, @@ -10222,17 +10226,13 @@ "deprecationReason": null }, { - "name": "tenantId", + "name": "tenant", "description": "Tenant of the webhook event.", "args": [], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } + "kind": "OBJECT", + "name": "Tenant", + "ofType": null }, "isDeprecated": false, "deprecationReason": null diff --git a/packages/backend/src/graphql/generated/graphql.ts b/packages/backend/src/graphql/generated/graphql.ts index 35e0959e56..e3b7f1e8aa 100644 --- a/packages/backend/src/graphql/generated/graphql.ts +++ b/packages/backend/src/graphql/generated/graphql.ts @@ -124,7 +124,8 @@ export type Asset = Model & { scale: Scalars['UInt8']['output']; /** The sending fee structure for the asset. */ sendingFee?: Maybe; - tenantId: Scalars['ID']['output']; + /** The tenant that the asset belongs to. */ + tenant?: Maybe; /** Minimum amount of liquidity that can be withdrawn from the asset. */ withdrawalThreshold?: Maybe; }; @@ -618,8 +619,8 @@ export type IncomingPayment = BasePayment & Model & { receivedAmount: Amount; /** State of the incoming payment. */ state: IncomingPaymentState; - /** The tenant UUID associated with the incoming payment. If not provided, it will be obtained from the signature. */ - tenantId?: Maybe; + /** The tenant associated with the incoming payment. If not provided, it will be obtained from the signature. */ + tenant?: Maybe; /** Unique identifier of the wallet address under which the incoming payment was created. */ walletAddressId: Scalars['ID']['output']; }; @@ -1034,8 +1035,8 @@ export type OutgoingPayment = BasePayment & Model & { state: OutgoingPaymentState; /** Number of attempts made to send an outgoing payment. */ stateAttempts: Scalars['Int']['output']; - /** Tenant ID of the outgoing payment. */ - tenantId?: Maybe; + /** Tenant of the outgoing payment. */ + tenant?: Maybe; /** Unique identifier of the wallet address under which the outgoing payment was created. */ walletAddressId: Scalars['ID']['output']; }; @@ -1110,6 +1111,8 @@ export type Payment = BasePayment & Model & { metadata?: Maybe; /** State of the payment, either `IncomingPaymentState` or `OutgoingPaymentState` according to payment type */ state: Scalars['String']['output']; + /** The tenant associated with the payment. */ + tenant?: Maybe; /** Type of payment, either incoming or outgoing. */ type: PaymentType; /** Unique identifier of the wallet address under which the payment was created. */ @@ -1167,7 +1170,7 @@ export type Peer = Model & { /** ILP address of the peer. */ staticIlpAddress: Scalars['String']['output']; /** Unique identifier of the tenant associated with the peer. */ - tenantId: Scalars['ID']['output']; + tenant?: Maybe; }; export type PeerEdge = { @@ -1668,8 +1671,8 @@ export type WalletAddress = Model & { quotes?: Maybe; /** The current status of the wallet, either active or inactive. */ status: WalletAddressStatus; - /** Tenant ID of the wallet address. */ - tenantId?: Maybe; + /** Tenant of the wallet address. */ + tenant?: Maybe; /** List of keys associated with this wallet address */ walletAddressKeys?: Maybe; }; @@ -1788,7 +1791,7 @@ export type WebhookEvent = Model & { /** Unique identifier of the webhook event. */ id: Scalars['ID']['output']; /** Tenant of the webhook event. */ - tenantId: Scalars['ID']['output']; + tenant?: Maybe; /** Type of webhook event. */ type: Scalars['String']['output']; }; @@ -2227,7 +2230,7 @@ export type AssetResolvers, ParentType, ContextType>; scale?: Resolver; sendingFee?: Resolver, ParentType, ContextType>; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; withdrawalThreshold?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2351,7 +2354,7 @@ export type IncomingPaymentResolvers, ParentType, ContextType>; receivedAmount?: Resolver; state?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2453,7 +2456,7 @@ export type OutgoingPaymentResolvers; state?: Resolver; stateAttempts?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2490,6 +2493,7 @@ export type PaymentResolvers, ParentType, ContextType>; metadata?: Resolver, ParentType, ContextType>; state?: Resolver; + tenant?: Resolver, ParentType, ContextType>; type?: Resolver; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -2517,7 +2521,7 @@ export type PeerResolvers, ParentType, ContextType>; name?: Resolver, ParentType, ContextType>; staticIlpAddress?: Resolver; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2679,7 +2683,7 @@ export type WalletAddressResolvers, ParentType, ContextType>; quotes?: Resolver, ParentType, ContextType, Partial>; status?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressKeys?: Resolver, ParentType, ContextType, Partial>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2733,7 +2737,7 @@ export type WebhookEventResolvers; data?: Resolver; id?: Resolver; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; type?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; diff --git a/packages/backend/src/graphql/resolvers/asset.test.ts b/packages/backend/src/graphql/resolvers/asset.test.ts index 12b6fdb2af..7b79cbb594 100644 --- a/packages/backend/src/graphql/resolvers/asset.test.ts +++ b/packages/backend/src/graphql/resolvers/asset.test.ts @@ -291,6 +291,9 @@ describe('Asset Resolvers', (): void => { withdrawalThreshold liquidityThreshold createdAt + tenant { + id + } } } `, @@ -314,7 +317,11 @@ describe('Asset Resolvers', (): void => { liquidity: '0', withdrawalThreshold: asset.withdrawalThreshold.toString(), liquidityThreshold: asset.liquidityThreshold?.toString(), - createdAt: new Date(+asset.createdAt).toISOString() + createdAt: new Date(+asset.createdAt).toISOString(), + tenant: { + __typename: 'Tenant', + id: asset.tenantId + } }) await accountingService.createDeposit({ @@ -331,7 +338,11 @@ describe('Asset Resolvers', (): void => { liquidity: '100', withdrawalThreshold: asset.withdrawalThreshold.toString(), liquidityThreshold: asset.liquidityThreshold?.toString(), - createdAt: new Date(+asset.createdAt).toISOString() + createdAt: new Date(+asset.createdAt).toISOString(), + tenant: { + __typename: 'Tenant', + id: asset.tenantId + } }) }) diff --git a/packages/backend/src/graphql/resolvers/asset.ts b/packages/backend/src/graphql/resolvers/asset.ts index c45f5d91b8..9eb2dc10bf 100644 --- a/packages/backend/src/graphql/resolvers/asset.ts +++ b/packages/backend/src/graphql/resolvers/asset.ts @@ -6,7 +6,12 @@ import { AssetResolvers } from '../generated/graphql' import { Asset } from '../../asset/model' -import { errorToCode, errorToMessage, isAssetError } from '../../asset/errors' +import { + AssetError, + errorToCode, + errorToMessage, + isAssetError +} from '../../asset/errors' import { ForTenantIdContext, TenantedApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' @@ -14,6 +19,7 @@ import { feeToGraphql } from './fee' import { Fee, FeeType } from '../../fee/model' import { GraphQLError } from 'graphql' import { GraphQLErrorCode } from '../errors' +import { tenantToGraphQl } from './tenant' export const getAssets: QueryResolvers['assets'] = async (parent, args, ctx): Promise => { @@ -185,6 +191,27 @@ export const getFees: AssetResolvers['fees'] = async ( } } +export const getAssetTenant: AssetResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id) + throw new GraphQLError( + '"id" field required in request to resolve "tenant".' + ) + const assetService = await ctx.container.use('assetService') + const asset = await assetService.get(parent.id) + if (!asset) + throw new GraphQLError(errorToCode[AssetError.UnknownAsset], { + extensions: { + code: errorToCode[AssetError.UnknownAsset] + } + }) + + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(asset.tenantId) + if (!tenant) return null + return tenantToGraphQl(tenant) + } + export const deleteAsset: MutationResolvers['deleteAsset'] = async ( _, @@ -216,6 +243,5 @@ export const assetToGraphql = (asset: Asset): SchemaAsset => ({ scale: asset.scale, withdrawalThreshold: asset.withdrawalThreshold, liquidityThreshold: asset.liquidityThreshold, - createdAt: new Date(+asset.createdAt).toISOString(), - tenantId: asset.tenantId + createdAt: new Date(+asset.createdAt).toISOString() }) diff --git a/packages/backend/src/graphql/resolvers/combined_payments.test.ts b/packages/backend/src/graphql/resolvers/combined_payments.test.ts index 8cea2d69c0..ad64e71fc0 100644 --- a/packages/backend/src/graphql/resolvers/combined_payments.test.ts +++ b/packages/backend/src/graphql/resolvers/combined_payments.test.ts @@ -94,6 +94,9 @@ describe('Payment', (): void => { state metadata createdAt + tenant { + id + } } cursor } @@ -129,7 +132,10 @@ describe('Payment', (): void => { client: combinedOutgoingPayment.client, state: combinedOutgoingPayment.state, createdAt: combinedOutgoingPayment.createdAt.toISOString(), - liquidity: '0' + liquidity: '0', + tenant: { + id: combinedOutgoingPayment.tenantId + } }) const combinedIncomingPayment = toCombinedPayment( @@ -144,7 +150,10 @@ describe('Payment', (): void => { client: combinedIncomingPayment.client, state: combinedIncomingPayment.state, createdAt: combinedIncomingPayment.createdAt.toISOString(), - liquidity: '0' + liquidity: '0', + tenant: { + id: combinedIncomingPayment.tenantId + } }) }) diff --git a/packages/backend/src/graphql/resolvers/combined_payments.ts b/packages/backend/src/graphql/resolvers/combined_payments.ts index 410045d5fc..7e887f4c9e 100644 --- a/packages/backend/src/graphql/resolvers/combined_payments.ts +++ b/packages/backend/src/graphql/resolvers/combined_payments.ts @@ -1,12 +1,28 @@ import { ResolversTypes, QueryResolvers, - Payment as SchemaPayment + Payment as SchemaPayment, + PaymentResolvers, + PaymentType } from '../generated/graphql' import { TenantedApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' import { CombinedPayment } from '../../open_payments/payment/combined/model' +import { tenantToGraphQl } from './tenant' +import { IncomingPayment } from '../../open_payments/payment/incoming/model' +import { OutgoingPayment } from '../../open_payments/payment/outgoing/model' +import { GraphQLError } from 'graphql' +import { + errorToCode as incomingPaymentErrorToCode, + errorToMessage as incomingPaymentErrorToMessage, + IncomingPaymentError +} from '../../open_payments/payment/incoming/errors' +import { + errorToCode as outgoingPaymentErrorToCode, + errorToMessage as outgoingPaymentErrorToMessage, + OutgoingPaymentError +} from '../../open_payments/payment/outgoing/errors' export const getCombinedPayments: QueryResolvers['payments'] = async (parent, args, ctx): Promise => { @@ -43,6 +59,60 @@ export const getCombinedPayments: QueryResolvers['payment } } +export const getPaymentTenant: PaymentResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id || !parent.type) + throw new GraphQLError( + '"id" and "type" fields required in request to resolve "tenant".' + ) + + let payment: IncomingPayment | OutgoingPayment + if (parent.type === PaymentType.Incoming) { + const incomingPaymentService = await ctx.container.use( + 'incomingPaymentService' + ) + const incomingPayment = await incomingPaymentService.get({ + id: parent.id + }) + if (!incomingPayment) + throw new GraphQLError( + incomingPaymentErrorToMessage[IncomingPaymentError.UnknownPayment], + { + extensions: { + code: incomingPaymentErrorToCode[ + IncomingPaymentError.UnknownPayment + ] + } + } + ) + payment = incomingPayment + } else { + const outgoingPaymentService = await ctx.container.use( + 'outgoingPaymentService' + ) + const outgoingPayment = await outgoingPaymentService.get({ + id: parent.id + }) + if (!outgoingPayment) + throw new GraphQLError( + outgoingPaymentErrorToMessage[OutgoingPaymentError.UnknownPayment], + { + extensions: { + code: outgoingPaymentErrorToCode[ + OutgoingPaymentError.UnknownPayment + ] + } + } + ) + payment = outgoingPayment + } + + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(payment.tenantId) + if (!tenant) return null + return tenantToGraphQl(tenant) + } + function paymentToGraphql(payment: CombinedPayment): SchemaPayment { return { id: payment.id, diff --git a/packages/backend/src/graphql/resolvers/incoming_payment.test.ts b/packages/backend/src/graphql/resolvers/incoming_payment.test.ts index 30cbfa893b..df5912f60a 100644 --- a/packages/backend/src/graphql/resolvers/incoming_payment.test.ts +++ b/packages/backend/src/graphql/resolvers/incoming_payment.test.ts @@ -421,6 +421,35 @@ describe('Incoming Payment Resolver', (): void => { __typename: 'IncomingPayment' }) }) + + test('with tenant', async (): Promise => { + const query = await appContainer.apolloClient + .query({ + query: gql` + query IncomingPayment($paymentId: String!) { + incomingPayment(id: $paymentId) { + id + tenant { + id + } + } + } + `, + variables: { + paymentId: payment.id + } + }) + .then((query): IncomingPayment => query.data?.incomingPayment) + + expect(query).toEqual({ + id: payment.id, + tenant: { + __typename: 'Tenant', + id: payment.tenantId + }, + __typename: 'IncomingPayment' + }) + }) }) test('not found', async (): Promise => { diff --git a/packages/backend/src/graphql/resolvers/incoming_payment.ts b/packages/backend/src/graphql/resolvers/incoming_payment.ts index eb77bc7691..884bad1b56 100644 --- a/packages/backend/src/graphql/resolvers/incoming_payment.ts +++ b/packages/backend/src/graphql/resolvers/incoming_payment.ts @@ -3,19 +3,22 @@ import { WalletAddressResolvers, MutationResolvers, IncomingPayment as SchemaIncomingPayment, - QueryResolvers + QueryResolvers, + IncomingPaymentResolvers } from '../generated/graphql' import { IncomingPayment } from '../../open_payments/payment/incoming/model' import { isIncomingPaymentError, errorToCode, - errorToMessage + errorToMessage, + IncomingPaymentError } from '../../open_payments/payment/incoming/errors' import { ForTenantIdContext, TenantedApolloContext } from '../../app' import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' import { GraphQLError } from 'graphql' import { GraphQLErrorCode } from '../errors' +import { tenantToGraphQl } from './tenant' export const getIncomingPayment: QueryResolvers['incomingPayment'] = async (parent, args, ctx): Promise => { @@ -199,6 +202,30 @@ export const cancelIncomingPayment: MutationResolvers['ca } } +export const getIncomingPaymentTenant: IncomingPaymentResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id) + throw new GraphQLError('"id" required in request to resolve "tenant".') + const incomingPaymentService = await ctx.container.use( + 'incomingPaymentService' + ) + const incomingPayment = await incomingPaymentService.get({ id: parent.id }) + if (!incomingPayment) + throw new GraphQLError( + errorToMessage[IncomingPaymentError.UnknownPayment], + { + extensions: { + code: errorToCode[IncomingPaymentError.UnknownPayment] + } + } + ) + + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(incomingPayment.tenantId) + if (!tenant) return null + return tenantToGraphQl(tenant) + } + export function paymentToGraphql( payment: IncomingPayment ): SchemaIncomingPayment { diff --git a/packages/backend/src/graphql/resolvers/index.ts b/packages/backend/src/graphql/resolvers/index.ts index 303b10dbee..f047bd3312 100644 --- a/packages/backend/src/graphql/resolvers/index.ts +++ b/packages/backend/src/graphql/resolvers/index.ts @@ -5,7 +5,8 @@ import { createWalletAddress, updateWalletAddress, triggerWalletAddressEvents, - getWalletAddressByUrl + getWalletAddressByUrl, + getWalletAddressTenant } from './wallet_address' import { getAsset, @@ -16,7 +17,8 @@ import { getAssetReceivingFee, getAssetSendingFee, getFees, - getAssetByCodeAndScale + getAssetByCodeAndScale, + getAssetTenant } from './asset' import { getWalletAddressIncomingPayments, @@ -24,7 +26,8 @@ import { getIncomingPayment, updateIncomingPayment, approveIncomingPayment, - cancelIncomingPayment + cancelIncomingPayment, + getIncomingPaymentTenant } from './incoming_payment' import { getQuote, createQuote, getWalletAddressQuotes } from './quote' import { @@ -33,7 +36,8 @@ import { createOutgoingPayment, getWalletAddressOutgoingPayments, createOutgoingPaymentFromIncomingPayment, - cancelOutgoingPayment + cancelOutgoingPayment, + getOutgoingPaymentTenant } from './outgoing_payment' import { getPeer, @@ -41,7 +45,8 @@ import { createPeer, updatePeer, deletePeer, - getPeerByAddressAndAsset + getPeerByAddressAndAsset, + getPeerTenant } from './peer' import { getAssetLiquidity, @@ -71,10 +76,10 @@ import { } from './walletAddressKey' import { getWalletAddressAdditionalProperties } from './walletAddressAdditionalProperties' import { createReceiver, getReceiver } from './receiver' -import { getWebhookEvents } from './webhooks' +import { getWebhookEvents, getWebhookEventTenant } from './webhooks' import { setFee } from './fee' import { GraphQLJSONObject } from 'graphql-scalars' -import { getCombinedPayments } from './combined_payments' +import { getCombinedPayments, getPaymentTenant } from './combined_payments' import { createOrUpdatePeerByUrl } from './auto-peering' import { getAccountingTransfers } from './accounting_transfer' import { @@ -95,10 +100,12 @@ export const resolvers: Resolvers = { liquidity: getAssetLiquidity, sendingFee: getAssetSendingFee, receivingFee: getAssetReceivingFee, - fees: getFees + fees: getFees, + tenant: getAssetTenant }, Peer: { - liquidity: getPeerLiquidity + liquidity: getPeerLiquidity, + tenant: getPeerTenant }, Query: { whoami, @@ -128,19 +135,26 @@ export const resolvers: Resolvers = { outgoingPayments: getWalletAddressOutgoingPayments, quotes: getWalletAddressQuotes, walletAddressKeys: getWalletAddressKeys, - additionalProperties: getWalletAddressAdditionalProperties + additionalProperties: getWalletAddressAdditionalProperties, + tenant: getWalletAddressTenant }, Tenant: { settings: getTenantSettings }, IncomingPayment: { - liquidity: getIncomingPaymentLiquidity + liquidity: getIncomingPaymentLiquidity, + tenant: getIncomingPaymentTenant }, OutgoingPayment: { - liquidity: getOutgoingPaymentLiquidity + liquidity: getOutgoingPaymentLiquidity, + tenant: getOutgoingPaymentTenant }, Payment: { - liquidity: getPaymentLiquidity + liquidity: getPaymentLiquidity, + tenant: getPaymentTenant + }, + WebhookEvent: { + tenant: getWebhookEventTenant }, Mutation: { createWalletAddressKey, diff --git a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts index 3d873333a2..edee9caea3 100644 --- a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts +++ b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts @@ -533,6 +533,35 @@ describe('OutgoingPayment Resolvers', (): void => { __typename: 'OutgoingPayment' }) }) + + test('with tenant', async (): Promise => { + const query = await appContainer.apolloClient + .query({ + query: gql` + query OutgoingPayment($paymentId: String!) { + outgoingPayment(id: $paymentId) { + id + tenant { + id + } + } + } + `, + variables: { + paymentId: payment.id + } + }) + .then((query): OutgoingPayment => query.data?.outgoingPayment) + + expect(query).toEqual({ + id: payment.id, + tenant: { + __typename: 'Tenant', + id: payment.tenantId + }, + __typename: 'OutgoingPayment' + }) + }) }) test('not found', async (): Promise => { diff --git a/packages/backend/src/graphql/resolvers/outgoing_payment.ts b/packages/backend/src/graphql/resolvers/outgoing_payment.ts index 7eb85b86ee..81b751b9af 100644 --- a/packages/backend/src/graphql/resolvers/outgoing_payment.ts +++ b/packages/backend/src/graphql/resolvers/outgoing_payment.ts @@ -4,9 +4,11 @@ import { OutgoingPayment as SchemaOutgoingPayment, WalletAddressResolvers, QueryResolvers, - ResolversTypes + ResolversTypes, + OutgoingPaymentResolvers } from '../generated/graphql' import { + OutgoingPaymentError, isOutgoingPaymentError, errorToMessage, errorToCode @@ -17,6 +19,7 @@ import { getPageInfo } from '../../shared/pagination' import { Pagination, SortOrder } from '../../shared/baseModel' import { GraphQLError } from 'graphql' import { GraphQLErrorCode } from '../errors' +import { tenantToGraphQl } from './tenant' export const getOutgoingPayment: QueryResolvers['outgoingPayment'] = async (parent, args, ctx): Promise => { @@ -230,6 +233,31 @@ export const getWalletAddressOutgoingPayments: WalletAddressResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id) + throw new GraphQLError('"id" required in request to resolve "tenant".') + const outgoingPaymentService = await ctx.container.use( + 'outgoingPaymentService' + ) + const outgoingPayment = await outgoingPaymentService.get({ id: parent.id }) + if (!outgoingPayment) + throw new GraphQLError( + errorToMessage[OutgoingPaymentError.UnknownPayment], + { + extensions: { + code: errorToCode[OutgoingPaymentError.UnknownPayment] + } + } + ) + + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(outgoingPayment.tenantId) + if (!tenant) return null + + return tenantToGraphQl(tenant) + } + export function paymentToGraphql( payment: OutgoingPayment ): SchemaOutgoingPayment { @@ -247,7 +275,6 @@ export function paymentToGraphql( metadata: payment.metadata, createdAt: new Date(+payment.createdAt).toISOString(), quote: quoteToGraphql(payment.quote), - grantId: payment.grantId, - tenantId: payment.tenantId + grantId: payment.grantId } } diff --git a/packages/backend/src/graphql/resolvers/peer.test.ts b/packages/backend/src/graphql/resolvers/peer.test.ts index 4794c9b57b..6c7e71dafc 100644 --- a/packages/backend/src/graphql/resolvers/peer.test.ts +++ b/packages/backend/src/graphql/resolvers/peer.test.ts @@ -270,6 +270,9 @@ describe('Peer Resolvers', (): void => { liquidity name liquidityThreshold + tenant { + id + } } } `, @@ -293,6 +296,10 @@ describe('Peer Resolvers', (): void => { code: peer.asset.code, scale: peer.asset.scale }, + tenant: { + __typename: 'Tenant', + id: peer.tenantId + }, http: { __typename: 'Http', outgoing: { @@ -321,6 +328,10 @@ describe('Peer Resolvers', (): void => { code: peer.asset.code, scale: peer.asset.scale }, + tenant: { + __typename: 'Tenant', + id: peer.tenantId + }, http: { __typename: 'Http', outgoing: { diff --git a/packages/backend/src/graphql/resolvers/peer.ts b/packages/backend/src/graphql/resolvers/peer.ts index 89862759d3..8e414333e5 100644 --- a/packages/backend/src/graphql/resolvers/peer.ts +++ b/packages/backend/src/graphql/resolvers/peer.ts @@ -1,9 +1,11 @@ import { assetToGraphql } from './asset' +import { tenantToGraphQl } from './tenant' import { QueryResolvers, ResolversTypes, Peer as SchemaPeer, - MutationResolvers + MutationResolvers, + PeerResolvers } from '../generated/graphql' import { Peer } from '../../payment-method/ilp/peer/model' import { @@ -142,6 +144,25 @@ export const deletePeer: MutationResolvers['deletePeer'] } } +export const getPeerTenant: PeerResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id) + throw new Error('"id" is required in request to resolve "tenant".') + + const peerService = await ctx.container.use('peerService') + const peer = await peerService.get(parent.id) + if (!peer) + throw new GraphQLError(errorToMessage[PeerError.UnknownPeer], { + extensions: { + code: errorToCode[PeerError.UnknownPeer] + } + }) + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(peer.tenantId) + if (!tenant) return null + return tenantToGraphQl(tenant) + } + export const peerToGraphql = (peer: Peer): SchemaPeer => ({ id: peer.id, maxPacketAmount: peer.maxPacketAmount, @@ -150,6 +171,5 @@ export const peerToGraphql = (peer: Peer): SchemaPeer => ({ staticIlpAddress: peer.staticIlpAddress, name: peer.name, liquidityThreshold: peer.liquidityThreshold, - createdAt: new Date(+peer.createdAt).toISOString(), - tenantId: peer.tenantId + createdAt: new Date(+peer.createdAt).toISOString() }) diff --git a/packages/backend/src/graphql/resolvers/wallet_address.test.ts b/packages/backend/src/graphql/resolvers/wallet_address.test.ts index 005bb2c421..0cb32b7804 100644 --- a/packages/backend/src/graphql/resolvers/wallet_address.test.ts +++ b/packages/backend/src/graphql/resolvers/wallet_address.test.ts @@ -909,6 +909,9 @@ describe('Wallet Address Resolvers', (): void => { value visibleInOpenPayments } + tenant { + id + } } } `, @@ -933,6 +936,10 @@ describe('Wallet Address Resolvers', (): void => { code: walletAddress.asset.code, scale: walletAddress.asset.scale }, + tenant: { + __typename: 'Tenant', + id: walletAddress.tenantId + }, address: walletAddress.address, publicName: publicName ?? null, additionalProperties: [ diff --git a/packages/backend/src/graphql/resolvers/wallet_address.ts b/packages/backend/src/graphql/resolvers/wallet_address.ts index 1fe36e61b7..ebc3d8edf3 100644 --- a/packages/backend/src/graphql/resolvers/wallet_address.ts +++ b/packages/backend/src/graphql/resolvers/wallet_address.ts @@ -6,7 +6,8 @@ import { ResolversTypes, WalletAddress as SchemaWalletAddress, MutationResolvers, - WalletAddressStatus + WalletAddressStatus, + WalletAddressResolvers } from '../generated/graphql' import { ForTenantIdContext, TenantedApolloContext } from '../../app' import { @@ -24,6 +25,7 @@ import { UpdateOptions } from '../../open_payments/wallet_address/service' import { GraphQLErrorCode } from '../errors' +import { tenantToGraphQl } from './tenant' export const getWalletAddresses: QueryResolvers['walletAddresses'] = async ( @@ -203,6 +205,29 @@ export const triggerWalletAddressEvents: MutationResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id) + throw new GraphQLError('"id" required in request to resolve "tenant".') + const walletAddressService = await ctx.container.use('walletAddressService') + const walletAddress = await walletAddressService.get(parent.id) + if (!walletAddress) + throw new GraphQLError( + errorToMessage[WalletAddressError.UnknownWalletAddress], + { + extensions: { + code: errorToCode[WalletAddressError.UnknownWalletAddress] + } + } + ) + + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(walletAddress.tenantId) + if (!tenant) return null + + return tenantToGraphQl(tenant) + } + export function walletAddressToGraphql( walletAddress: WalletAddress ): SchemaWalletAddress { @@ -214,7 +239,6 @@ export function walletAddressToGraphql( createdAt: new Date(+walletAddress.createdAt).toISOString(), status: walletAddress.isActive ? WalletAddressStatus.Active - : WalletAddressStatus.Inactive, - tenantId: walletAddress.tenantId + : WalletAddressStatus.Inactive } } diff --git a/packages/backend/src/graphql/resolvers/webhooks.test.ts b/packages/backend/src/graphql/resolvers/webhooks.test.ts index 9c205c92aa..14a9cf65d1 100644 --- a/packages/backend/src/graphql/resolvers/webhooks.test.ts +++ b/packages/backend/src/graphql/resolvers/webhooks.test.ts @@ -63,6 +63,9 @@ describe('Webhook Events Query', (): void => { id type data + tenant { + id + } } cursor } @@ -87,7 +90,11 @@ describe('Webhook Events Query', (): void => { __typename: 'WebhookEvent', id: webhookEvent.id, type: webhookEvent.type, - data: webhookEvent.data + data: webhookEvent.data, + tenant: { + __typename: 'Tenant', + id: webhookEvent.tenantId + } }) }) }) diff --git a/packages/backend/src/graphql/resolvers/webhooks.ts b/packages/backend/src/graphql/resolvers/webhooks.ts index cfd514af9d..d7ab9000a8 100644 --- a/packages/backend/src/graphql/resolvers/webhooks.ts +++ b/packages/backend/src/graphql/resolvers/webhooks.ts @@ -2,11 +2,15 @@ import { TenantedApolloContext } from '../../app' import { QueryResolvers, ResolversTypes, - WebhookEvent as SchemaWebhookEvent + WebhookEvent as SchemaWebhookEvent, + WebhookEventResolvers } from '../generated/graphql' import { getPageInfo } from '../../shared/pagination' import { WebhookEvent } from '../../webhook/event/model' import { Pagination, SortOrder } from '../../shared/baseModel' +import { tenantToGraphQl } from './tenant' +import { GraphQLError } from 'graphql' +import { errorToCode, errorToMessage, WebhookError } from '../../webhook/errors' export const getWebhookEvents: QueryResolvers['webhookEvents'] = async ( @@ -40,12 +44,28 @@ export const getWebhookEvents: QueryResolvers['webhookEve } } +export const getWebhookEventTenant: WebhookEventResolvers['tenant'] = + async (parent, args, ctx): Promise => { + if (!parent.id) return null + const webhookService = await ctx.container.use('webhookService') + const webhookEvent = await webhookService.getEvent(parent.id) + if (!webhookEvent) + throw new GraphQLError(errorToMessage[WebhookError.UnknownWebhookEvent], { + extensions: { + code: errorToCode[WebhookError.UnknownWebhookEvent] + } + }) + const tenantService = await ctx.container.use('tenantService') + const tenant = await tenantService.get(webhookEvent.tenantId) + if (!tenant) return null + return tenantToGraphQl(tenant) + } + export const webhookEventToGraphql = ( webhookEvent: WebhookEvent ): SchemaWebhookEvent => ({ id: webhookEvent.id, type: webhookEvent.type, data: webhookEvent.data, - tenantId: webhookEvent.tenantId, createdAt: new Date(webhookEvent.createdAt).toISOString() }) diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index 4750a2b300..013e4a7a91 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -697,7 +697,8 @@ type Asset implements Model { ): FeesConnection "The date and time when the asset was created." createdAt: String! - tenantId: ID! + "The tenant that the asset belongs to." + tenant: Tenant } enum SortOrder { @@ -754,7 +755,7 @@ type Peer implements Model { "The date and time when the peer was created." createdAt: String! "Unique identifier of the tenant associated with the peer." - tenantId: ID! + tenant: Tenant } input DeletePeerInput { @@ -871,8 +872,8 @@ type WalletAddress implements Model { "Additional properties associated with the wallet address." additionalProperties: [AdditionalProperty] - "Tenant ID of the wallet address." - tenantId: String + "Tenant of the wallet address." + tenant: Tenant } type AdditionalProperty { @@ -953,8 +954,8 @@ type IncomingPayment implements BasePayment & Model { metadata: JSONObject "The date and time that the incoming payment was created." createdAt: String! - "The tenant UUID associated with the incoming payment. If not provided, it will be obtained from the signature." - tenantId: String + "The tenant associated with the incoming payment. If not provided, it will be obtained from the signature." + tenant: Tenant } type Receiver { @@ -1050,8 +1051,8 @@ type OutgoingPayment implements BasePayment & Model { createdAt: String! "Unique identifier of the grant under which the outgoing payment was created." grantId: String - "Tenant ID of the outgoing payment." - tenantId: String + "Tenant of the outgoing payment." + tenant: Tenant } enum OutgoingPaymentState { @@ -1098,6 +1099,8 @@ type Payment implements BasePayment & Model { metadata: JSONObject "The date and time that the payment was created." createdAt: String! + "The tenant associated with the payment." + tenant: Tenant } enum PaymentType { @@ -1397,7 +1400,7 @@ type WebhookEvent implements Model { "Unique identifier of the webhook event." id: ID! "Tenant of the webhook event." - tenantId: ID! + tenant: Tenant "Type of webhook event." type: String! "Stringified JSON data for the webhook event." diff --git a/packages/backend/src/open_payments/payment/incoming/model.test.ts b/packages/backend/src/open_payments/payment/incoming/model.test.ts index 2654c4ae33..759bf7e042 100644 --- a/packages/backend/src/open_payments/payment/incoming/model.test.ts +++ b/packages/backend/src/open_payments/payment/incoming/model.test.ts @@ -63,7 +63,7 @@ describe('Models', (): void => { walletAddress ) ).toEqual({ - id: `${baseUrl}/${incomingPayment.tenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, + id: `${baseUrl}/${Config.operatorTenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, walletAddress: walletAddress.address, completed: incomingPayment.completed, receivedAmount: serializeAmount(incomingPayment.receivedAmount), @@ -94,7 +94,7 @@ describe('Models', (): void => { paymentMethods ) ).toEqual({ - id: `${baseUrl}/${incomingPayment.tenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, + id: `${baseUrl}/${Config.operatorTenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, walletAddress: walletAddress.address, completed: incomingPayment.completed, receivedAmount: serializeAmount(incomingPayment.receivedAmount), diff --git a/packages/backend/src/webhook/errors.ts b/packages/backend/src/webhook/errors.ts new file mode 100644 index 0000000000..9d0b87ed21 --- /dev/null +++ b/packages/backend/src/webhook/errors.ts @@ -0,0 +1,17 @@ +import { GraphQLErrorCode } from '../graphql/errors' + +export enum WebhookError { + UnknownWebhookEvent = 'UnknownWebhookEvent' +} + +export const errorToCode: { + [key in WebhookError]: GraphQLErrorCode +} = { + [WebhookError.UnknownWebhookEvent]: GraphQLErrorCode.NotFound +} + +export const errorToMessage: { + [key in WebhookError]: string +} = { + [WebhookError.UnknownWebhookEvent]: 'unknown webhook event' +} diff --git a/packages/frontend/app/generated/graphql.ts b/packages/frontend/app/generated/graphql.ts index 89a4198ca4..b626dc969a 100644 --- a/packages/frontend/app/generated/graphql.ts +++ b/packages/frontend/app/generated/graphql.ts @@ -124,7 +124,8 @@ export type Asset = Model & { scale: Scalars['UInt8']['output']; /** The sending fee structure for the asset. */ sendingFee?: Maybe; - tenantId: Scalars['ID']['output']; + /** The tenant that the asset belongs to. */ + tenant?: Maybe; /** Minimum amount of liquidity that can be withdrawn from the asset. */ withdrawalThreshold?: Maybe; }; @@ -618,8 +619,8 @@ export type IncomingPayment = BasePayment & Model & { receivedAmount: Amount; /** State of the incoming payment. */ state: IncomingPaymentState; - /** The tenant UUID associated with the incoming payment. If not provided, it will be obtained from the signature. */ - tenantId?: Maybe; + /** The tenant associated with the incoming payment. If not provided, it will be obtained from the signature. */ + tenant?: Maybe; /** Unique identifier of the wallet address under which the incoming payment was created. */ walletAddressId: Scalars['ID']['output']; }; @@ -1034,8 +1035,8 @@ export type OutgoingPayment = BasePayment & Model & { state: OutgoingPaymentState; /** Number of attempts made to send an outgoing payment. */ stateAttempts: Scalars['Int']['output']; - /** Tenant ID of the outgoing payment. */ - tenantId?: Maybe; + /** Tenant of the outgoing payment. */ + tenant?: Maybe; /** Unique identifier of the wallet address under which the outgoing payment was created. */ walletAddressId: Scalars['ID']['output']; }; @@ -1110,6 +1111,8 @@ export type Payment = BasePayment & Model & { metadata?: Maybe; /** State of the payment, either `IncomingPaymentState` or `OutgoingPaymentState` according to payment type */ state: Scalars['String']['output']; + /** The tenant associated with the payment. */ + tenant?: Maybe; /** Type of payment, either incoming or outgoing. */ type: PaymentType; /** Unique identifier of the wallet address under which the payment was created. */ @@ -1167,7 +1170,7 @@ export type Peer = Model & { /** ILP address of the peer. */ staticIlpAddress: Scalars['String']['output']; /** Unique identifier of the tenant associated with the peer. */ - tenantId: Scalars['ID']['output']; + tenant?: Maybe; }; export type PeerEdge = { @@ -1668,8 +1671,8 @@ export type WalletAddress = Model & { quotes?: Maybe; /** The current status of the wallet, either active or inactive. */ status: WalletAddressStatus; - /** Tenant ID of the wallet address. */ - tenantId?: Maybe; + /** Tenant of the wallet address. */ + tenant?: Maybe; /** List of keys associated with this wallet address */ walletAddressKeys?: Maybe; }; @@ -1788,7 +1791,7 @@ export type WebhookEvent = Model & { /** Unique identifier of the webhook event. */ id: Scalars['ID']['output']; /** Tenant of the webhook event. */ - tenantId: Scalars['ID']['output']; + tenant?: Maybe; /** Type of webhook event. */ type: Scalars['String']['output']; }; @@ -2227,7 +2230,7 @@ export type AssetResolvers, ParentType, ContextType>; scale?: Resolver; sendingFee?: Resolver, ParentType, ContextType>; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; withdrawalThreshold?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2351,7 +2354,7 @@ export type IncomingPaymentResolvers, ParentType, ContextType>; receivedAmount?: Resolver; state?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2453,7 +2456,7 @@ export type OutgoingPaymentResolvers; state?: Resolver; stateAttempts?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2490,6 +2493,7 @@ export type PaymentResolvers, ParentType, ContextType>; metadata?: Resolver, ParentType, ContextType>; state?: Resolver; + tenant?: Resolver, ParentType, ContextType>; type?: Resolver; walletAddressId?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -2517,7 +2521,7 @@ export type PeerResolvers, ParentType, ContextType>; name?: Resolver, ParentType, ContextType>; staticIlpAddress?: Resolver; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2679,7 +2683,7 @@ export type WalletAddressResolvers, ParentType, ContextType>; quotes?: Resolver, ParentType, ContextType, Partial>; status?: Resolver; - tenantId?: Resolver, ParentType, ContextType>; + tenant?: Resolver, ParentType, ContextType>; walletAddressKeys?: Resolver, ParentType, ContextType, Partial>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2733,7 +2737,7 @@ export type WebhookEventResolvers; data?: Resolver; id?: Resolver; - tenantId?: Resolver; + tenant?: Resolver, ParentType, ContextType>; type?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -2861,7 +2865,7 @@ export type ListAssetsQueryVariables = Exact<{ }>; -export type ListAssetsQuery = { __typename?: 'Query', assets: { __typename?: 'AssetsConnection', edges: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', code: string, id: string, scale: number, withdrawalThreshold?: bigint | null, createdAt: string, tenantId: string } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; +export type ListAssetsQuery = { __typename?: 'Query', assets: { __typename?: 'AssetsConnection', edges: Array<{ __typename?: 'AssetEdge', node: { __typename?: 'Asset', code: string, id: string, scale: number, withdrawalThreshold?: bigint | null, createdAt: string, tenant?: { __typename?: 'Tenant', id: string, publicName?: string | null } | null } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; export type CreateAssetMutationVariables = Exact<{ input: CreateAssetInput; @@ -2928,7 +2932,7 @@ export type ListPaymentsQueryVariables = Exact<{ }>; -export type ListPaymentsQuery = { __typename?: 'Query', payments: { __typename?: 'PaymentConnection', edges: Array<{ __typename?: 'PaymentEdge', node: { __typename?: 'Payment', id: string, type: PaymentType, state: string, createdAt: string } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; +export type ListPaymentsQuery = { __typename?: 'Query', payments: { __typename?: 'PaymentConnection', edges: Array<{ __typename?: 'PaymentEdge', node: { __typename?: 'Payment', id: string, type: PaymentType, state: string, createdAt: string, tenant?: { __typename?: 'Tenant', id: string, publicName?: string | null } | null } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; export type DepositOutgoingPaymentLiquidityVariables = Exact<{ input: DepositOutgoingPaymentLiquidityInput; @@ -2966,7 +2970,7 @@ export type ListPeersQueryVariables = Exact<{ }>; -export type ListPeersQuery = { __typename?: 'Query', peers: { __typename?: 'PeersConnection', edges: Array<{ __typename?: 'PeerEdge', node: { __typename?: 'Peer', id: string, name?: string | null, staticIlpAddress: string, http: { __typename?: 'Http', outgoing: { __typename?: 'HttpOutgoing', endpoint: string } }, asset: { __typename?: 'Asset', code: string, scale: number } } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; +export type ListPeersQuery = { __typename?: 'Query', peers: { __typename?: 'PeersConnection', edges: Array<{ __typename?: 'PeerEdge', node: { __typename?: 'Peer', id: string, name?: string | null, staticIlpAddress: string, http: { __typename?: 'Http', outgoing: { __typename?: 'HttpOutgoing', endpoint: string } }, asset: { __typename?: 'Asset', code: string, scale: number }, tenant?: { __typename?: 'Tenant', id: string, publicName?: string | null } | null } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; export type CreatePeerMutationVariables = Exact<{ input: CreatePeerInput; @@ -3061,7 +3065,7 @@ export type ListWalletAddresssQueryVariables = Exact<{ }>; -export type ListWalletAddresssQuery = { __typename?: 'Query', walletAddresses: { __typename?: 'WalletAddressesConnection', edges: Array<{ __typename?: 'WalletAddressEdge', cursor: string, node: { __typename?: 'WalletAddress', id: string, publicName?: string | null, status: WalletAddressStatus, address: string } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; +export type ListWalletAddresssQuery = { __typename?: 'Query', walletAddresses: { __typename?: 'WalletAddressesConnection', edges: Array<{ __typename?: 'WalletAddressEdge', cursor: string, node: { __typename?: 'WalletAddress', id: string, publicName?: string | null, status: WalletAddressStatus, address: string, tenant?: { __typename?: 'Tenant', id: string, publicName?: string | null } | null } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; export type UpdateWalletAddressMutationVariables = Exact<{ input: UpdateWalletAddressInput; @@ -3093,4 +3097,4 @@ export type ListWebhookEventsVariables = Exact<{ }>; -export type ListWebhookEvents = { __typename?: 'Query', webhookEvents: { __typename?: 'WebhookEventsConnection', edges: Array<{ __typename?: 'WebhookEventsEdge', cursor: string, node: { __typename?: 'WebhookEvent', id: string, tenantId: string, data: any, type: string, createdAt: string } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; +export type ListWebhookEvents = { __typename?: 'Query', webhookEvents: { __typename?: 'WebhookEventsConnection', edges: Array<{ __typename?: 'WebhookEventsEdge', cursor: string, node: { __typename?: 'WebhookEvent', id: string, data: any, type: string, createdAt: string, tenant?: { __typename?: 'Tenant', id: string, publicName?: string | null } | null } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; diff --git a/packages/frontend/app/lib/api/asset.server.ts b/packages/frontend/app/lib/api/asset.server.ts index b4cae9fa02..c07a81ba0d 100644 --- a/packages/frontend/app/lib/api/asset.server.ts +++ b/packages/frontend/app/lib/api/asset.server.ts @@ -123,7 +123,10 @@ export const listAssets = async (request: Request, args: QueryAssetsArgs) => { scale withdrawalThreshold createdAt - tenantId + tenant { + id + publicName + } } } pageInfo { diff --git a/packages/frontend/app/lib/api/payments.server.ts b/packages/frontend/app/lib/api/payments.server.ts index 3f6fae93f7..0c2752ba8d 100644 --- a/packages/frontend/app/lib/api/payments.server.ts +++ b/packages/frontend/app/lib/api/payments.server.ts @@ -133,6 +133,10 @@ export const listPayments = async ( type state createdAt + tenant { + id + publicName + } } } pageInfo { diff --git a/packages/frontend/app/lib/api/peer.server.ts b/packages/frontend/app/lib/api/peer.server.ts index 19ba5fc5a0..41da7a5000 100644 --- a/packages/frontend/app/lib/api/peer.server.ts +++ b/packages/frontend/app/lib/api/peer.server.ts @@ -88,6 +88,10 @@ export const listPeers = async (request: Request, args: QueryPeersArgs) => { code scale } + tenant { + id + publicName + } } } pageInfo { diff --git a/packages/frontend/app/lib/api/wallet-address.server.ts b/packages/frontend/app/lib/api/wallet-address.server.ts index 4ce2733911..e1bf228417 100644 --- a/packages/frontend/app/lib/api/wallet-address.server.ts +++ b/packages/frontend/app/lib/api/wallet-address.server.ts @@ -78,6 +78,10 @@ export const listWalletAddresses = async ( publicName status address + tenant { + id + publicName + } } } pageInfo { diff --git a/packages/frontend/app/lib/api/webhook.server.ts b/packages/frontend/app/lib/api/webhook.server.ts index bc45276cf4..b19c8f79dc 100644 --- a/packages/frontend/app/lib/api/webhook.server.ts +++ b/packages/frontend/app/lib/api/webhook.server.ts @@ -34,10 +34,13 @@ export const listWebhooks = async ( cursor node { id - tenantId data type createdAt + tenant { + id + publicName + } } } pageInfo { diff --git a/packages/frontend/app/routes/assets._index.tsx b/packages/frontend/app/routes/assets._index.tsx index 758f40d613..ed44da6f70 100644 --- a/packages/frontend/app/routes/assets._index.tsx +++ b/packages/frontend/app/routes/assets._index.tsx @@ -57,7 +57,7 @@ export default function AssetsPage() { {assets.edges.length ? ( @@ -79,6 +79,26 @@ export default function AssetsPage() { )} + +
+
+ + {asset.node.tenant?.publicName ? ( + + {asset.node.tenant.publicName} + + ) : ( + + No public name + + )} + +
+ (ID: {asset.node.tenant?.id}) +
+
+
+
)) ) : ( diff --git a/packages/frontend/app/routes/payments._index.tsx b/packages/frontend/app/routes/payments._index.tsx index 9c57ca2512..4c16a414e1 100644 --- a/packages/frontend/app/routes/payments._index.tsx +++ b/packages/frontend/app/routes/payments._index.tsx @@ -218,7 +218,7 @@ export default function PaymentsPage() {
- + {payments.edges.length ? ( payments.edges.map((payment) => ( @@ -246,6 +246,26 @@ export default function PaymentsPage() { {new Date(payment.node.createdAt).toLocaleString()} + +
+
+ + {payment.node.tenant?.publicName ? ( + + {payment.node.tenant.publicName} + + ) : ( + + No public name + + )} + +
+ (ID: {payment.node.tenant?.id}) +
+
+
+
)) ) : ( diff --git a/packages/frontend/app/routes/peers._index.tsx b/packages/frontend/app/routes/peers._index.tsx index a8d201f4f6..f102800baa 100644 --- a/packages/frontend/app/routes/peers._index.tsx +++ b/packages/frontend/app/routes/peers._index.tsx @@ -5,6 +5,7 @@ import { Button, Table } from '~/components/ui' import { listPeers } from '~/lib/api/peer.server' import { paginationSchema } from '~/lib/validate.server' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' +import { truncateUuid } from '~/shared/utils' export const loader = async ({ request }: LoaderFunctionArgs) => { const cookies = request.headers.get('cookie') @@ -57,7 +58,13 @@ export default function PeersPage() {
{peers.edges.length ? ( @@ -84,6 +91,26 @@ export default function PeersPage() { {peer.node.asset.code} (Scale: {peer.node.asset.scale}) {peer.node.http.outgoing.endpoint} + +
+
+ + {peer.node.tenant?.publicName ? ( + + {peer.node.tenant.publicName} + + ) : ( + + No public name + + )} + +
+ (ID: {truncateUuid(peer.node.tenant?.id as string)}) +
+
+
+
)) ) : ( diff --git a/packages/frontend/app/routes/peers.create.tsx b/packages/frontend/app/routes/peers.create.tsx index eaa520e2d4..37de58cfef 100644 --- a/packages/frontend/app/routes/peers.create.tsx +++ b/packages/frontend/app/routes/peers.create.tsx @@ -47,7 +47,7 @@ export default function CreatePeerPage() { const getAssetsOfTenant = (): SelectOption[] => { const assetsOfTenant = assets.filter( - (asset) => asset.node.tenantId === tenantId?.value + (asset) => asset.node.tenant?.id === tenantId?.value ) return assetsOfTenant.map((asset) => ({ value: asset.node.id, diff --git a/packages/frontend/app/routes/wallet-addresses._index.tsx b/packages/frontend/app/routes/wallet-addresses._index.tsx index e5946d0ca4..3ba90e149e 100644 --- a/packages/frontend/app/routes/wallet-addresses._index.tsx +++ b/packages/frontend/app/routes/wallet-addresses._index.tsx @@ -60,21 +60,23 @@ export default function WalletAddressesPage() {
- + {walletAddresses.edges.length ? ( - walletAddresses.edges.map((pp) => ( + walletAddresses.edges.map((wa) => ( navigate(`/wallet-addresses/${pp.node.id}`)} + onClick={() => navigate(`/wallet-addresses/${wa.node.id}`)} > - {pp.node.address} + {wa.node.address}
- {pp.node.publicName ? ( + {wa.node.publicName ? ( - {pp.node.publicName} + {wa.node.publicName} ) : ( No public name @@ -83,11 +85,31 @@ export default function WalletAddressesPage() { - {pp.node.status} + {wa.node.status} + +
+
+ + {wa.node.tenant?.publicName ? ( + + {wa.node.tenant.publicName} + + ) : ( + + No public name + + )} + +
+ (ID: {wa.node.tenant?.id}) +
+
+
+
)) ) : ( diff --git a/packages/frontend/app/routes/wallet-addresses.create.tsx b/packages/frontend/app/routes/wallet-addresses.create.tsx index b199ef44da..94a790d67e 100644 --- a/packages/frontend/app/routes/wallet-addresses.create.tsx +++ b/packages/frontend/app/routes/wallet-addresses.create.tsx @@ -44,7 +44,7 @@ export default function CreateWalletAddressPage() { const getAssetsOfTenant = (): SelectOption[] => { const assetsOfTenant = assets.filter( - (asset) => asset.node.tenantId === tenantId?.value + (asset) => asset.node.tenant?.id === tenantId?.value ) return assetsOfTenant.map((asset) => ({ value: asset.node.id, diff --git a/packages/frontend/app/routes/webhook-events.tsx b/packages/frontend/app/routes/webhook-events.tsx index d2129223da..9dee6b124c 100644 --- a/packages/frontend/app/routes/webhook-events.tsx +++ b/packages/frontend/app/routes/webhook-events.tsx @@ -12,6 +12,7 @@ import { listWebhooks } from '~/lib/api/webhook.server' import { webhooksSearchParams } from '~/lib/validate.server' import { WebhookEventType } from '~/shared/enums' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' +import { truncateUuid } from '~/shared/utils' export const loader = async ({ request }: LoaderFunctionArgs) => { const cookies = request.headers.get('cookie') @@ -119,7 +120,7 @@ export default function WebhookEventsPage() {
- + {webhooks.edges.length ? ( webhooks.edges.map((webhook) => ( @@ -129,13 +130,34 @@ export default function WebhookEventsPage() { {new Date(webhook.node.createdAt).toLocaleString()} + + +
+ + {webhook.node.tenant?.publicName ? ( + + {webhook.node.tenant.publicName} + + ) : ( + + No public name + + )} + +
+ (ID:{' '} + {truncateUuid(webhook.node.tenant?.id as string)}) +
+
+
+