Skip to content

Commit 8ff0b75

Browse files
tiankiiesaugomez31dolcalmi
authored
feat: add ln address support for contacts (#85)
* feat(core): add ContactsRepository with persist, find and update methods * chore(core|services): repository function requesting object parameters * chore: refactored contact collection * feat: graphql accountContactUpsert mutation, initial version * chore: file to updated and add contact renamed * refactor: move contact storage from accounts collection to dedicated contacts collection * feat(core): migrate-contacts-to-collection * test(core|e2e): test upsert contact mutation * chore: remove personal data * chore: renaming mutation accountContactUpsert to contactCreate * chore: renamin contact with upsert references * refactor: referencing the contacts collection in accounts object * refactor(account): remove contacts field from Account schema * fix(migrations): avoid redeclaration of randomUUID in contact to collection migration * refactor(graphql): rename Contact.identifier to handle and Contact.alias to displayName * refactor(contacts): clean schema and rename repository methods * refactor(contacts): clean up embedded contacts after migration * refactor(graphql): rename contact-create.ts to contact.ts to match object name * refactor(contacts): unify contact creation logic and align with app conventions * refactor(account): remove contact query from translateToAccount * chore(e2e): clean test description to contacts * chore(migration): move contacts unset operation to separate migration * refactor(domain): unify handle validation and remove casts from domain layer * fix: using handle type to contacts vars * chore: remove migration of unset contacts to a separate pr * refactor(contacts): rename validation functions and enhance contact error handling * fix: solve graphql generated file conflicts * feat(core): contact ValidationInternalError to error-map * refactor(core): use accountId in getContactByHandle * test(e2e): update is_contact helper to use same contacts query as blink-mobile * refactor: deprecate username and include handle in AccountContact response * fix: update contact repository interface * fix: contact payload name * fix: contact display name default value * fix: remove toLightningAddress * fix: use 1 param rule in getContactsByAccountId --------- Co-authored-by: Esaú Gómez <[email protected]> Co-authored-by: Juan P Lopez <[email protected]>
1 parent 8df2aca commit 8ff0b75

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1366
-195
lines changed

apps/consent/app/graphql/generated.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export type Scalars = {
2323
CentAmount: { input: number; output: number; }
2424
/** An alias name that a user can set for a wallet (with which they have transactions) */
2525
ContactAlias: { input: string; output: string; }
26+
/** A display name that a user can assign to a contact */
27+
ContactDisplayName: { input: string; output: string; }
28+
/** Unique handle used to identify a contact (e.g., username or lnAddress) */
29+
ContactHandle: { input: string; output: string; }
30+
/** Unique identifier of a contact */
31+
ContactId: { input: string; output: string; }
2632
/** A CCA2 country code (ex US, FR, etc) */
2733
CountryCode: { input: string; output: string; }
2834
/** Display currency of an account */
@@ -418,6 +424,40 @@ export type ConsumerAccountWalletByIdArgs = {
418424
walletId: Scalars['WalletId']['input'];
419425
};
420426

427+
export type Contact = {
428+
readonly __typename: 'Contact';
429+
/** Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) */
430+
readonly createdAt: Scalars['Timestamp']['output'];
431+
/** DisplayName name the user assigns to the contact. */
432+
readonly displayName?: Maybe<Scalars['ContactDisplayName']['output']>;
433+
/** Username or lnAddress that identifies the contact. */
434+
readonly handle: Scalars['ContactHandle']['output'];
435+
/** ID of the contact user or external handle. */
436+
readonly id: Scalars['ContactId']['output'];
437+
/** Total number of transactions with this contact. */
438+
readonly transactionsCount: Scalars['Int']['output'];
439+
/** Type of the contact (intraledger, lnaddress, etc.). */
440+
readonly type: ContactType;
441+
};
442+
443+
export type ContactCreateInput = {
444+
readonly displayName?: InputMaybe<Scalars['ContactAlias']['input']>;
445+
readonly handle?: InputMaybe<Scalars['ContactHandle']['input']>;
446+
readonly type: ContactType;
447+
};
448+
449+
export type ContactPayload = {
450+
readonly __typename: 'ContactPayload';
451+
readonly contact?: Maybe<Contact>;
452+
readonly errors: ReadonlyArray<Error>;
453+
};
454+
455+
export const ContactType = {
456+
Intraledger: 'INTRALEDGER',
457+
Lnaddress: 'LNADDRESS'
458+
} as const;
459+
460+
export type ContactType = typeof ContactType[keyof typeof ContactType];
421461
export type Coordinates = {
422462
readonly __typename: 'Coordinates';
423463
readonly latitude: Scalars['Float']['output'];
@@ -900,6 +940,7 @@ export type Mutation = {
900940
readonly callbackEndpointDelete: SuccessPayload;
901941
readonly captchaCreateChallenge: CaptchaCreateChallengePayload;
902942
readonly captchaRequestAuthCode: SuccessPayload;
943+
readonly contactCreate: ContactPayload;
903944
readonly deviceNotificationTokenCreate: SuccessPayload;
904945
readonly feedbackSubmit: SuccessPayload;
905946
/**
@@ -1062,6 +1103,11 @@ export type MutationCaptchaRequestAuthCodeArgs = {
10621103
};
10631104

10641105

1106+
export type MutationContactCreateArgs = {
1107+
input: ContactCreateInput;
1108+
};
1109+
1110+
10651111
export type MutationDeviceNotificationTokenCreateArgs = {
10661112
input: DeviceNotificationTokenCreateInput;
10671113
};
@@ -1962,11 +2008,16 @@ export type UserContact = {
19622008
* Only the user can see the alias attached to their contact.
19632009
*/
19642010
readonly alias?: Maybe<Scalars['ContactAlias']['output']>;
1965-
readonly id: Scalars['Username']['output'];
2011+
/** Identifier of the contact (username or Lightning address). */
2012+
readonly handle: Scalars['ContactHandle']['output'];
2013+
readonly id: Scalars['ContactHandle']['output'];
19662014
/** Paginated list of transactions sent to/from this contact. */
19672015
readonly transactions?: Maybe<TransactionConnection>;
19682016
readonly transactionsCount: Scalars['Int']['output'];
1969-
/** Actual identifier of the contact. */
2017+
/**
2018+
* Actual identifier of the contact. Deprecated: use `handle` instead.
2019+
* @deprecated Use `handle` field; this will be removed in a future release.
2020+
*/
19702021
readonly username: Scalars['Username']['output'];
19712022
};
19722023

apps/consent/codegen.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,8 @@ generates:
6060
EndpointUrl: "string"
6161
Object: "string"
6262
NotificationCategory: "string"
63+
AccountId: "string"
64+
ContactId: "string"
65+
ContactHandle: "string"
66+
ContactType: "string"
67+
ContactDisplayName: "string"

apps/dashboard/codegen.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,8 @@ generates:
6969
EndpointUrl: "string"
7070
NotificationCategory: "string"
7171
DateTime: "string"
72+
AccountId: "string"
73+
ContactId: "string"
74+
ContactHandle: "string"
75+
ContactType: "string"
76+
ContactDisplayName: "string"

apps/dashboard/services/graphql/generated.ts

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ export type Scalars = {
2626
CentAmount: { input: number; output: number; }
2727
/** An alias name that a user can set for a wallet (with which they have transactions) */
2828
ContactAlias: { input: string; output: string; }
29+
/** A display name that a user can assign to a contact */
30+
ContactDisplayName: { input: string; output: string; }
31+
/** Unique handle used to identify a contact (e.g., username or lnAddress) */
32+
ContactHandle: { input: string; output: string; }
33+
/** Unique identifier of a contact */
34+
ContactId: { input: string; output: string; }
2935
/** A CCA2 country code (ex US, FR, etc) */
3036
CountryCode: { input: string; output: string; }
3137
/** Display currency of an account */
@@ -458,6 +464,40 @@ export type ConsumerAccountWalletByIdArgs = {
458464
walletId: Scalars['WalletId']['input'];
459465
};
460466

467+
export type Contact = {
468+
readonly __typename: 'Contact';
469+
/** Unix timestamp (number of seconds elapsed since January 1, 1970 00:00:00 UTC) */
470+
readonly createdAt: Scalars['Timestamp']['output'];
471+
/** DisplayName name the user assigns to the contact. */
472+
readonly displayName?: Maybe<Scalars['ContactDisplayName']['output']>;
473+
/** Username or lnAddress that identifies the contact. */
474+
readonly handle: Scalars['ContactHandle']['output'];
475+
/** ID of the contact user or external handle. */
476+
readonly id: Scalars['ContactId']['output'];
477+
/** Total number of transactions with this contact. */
478+
readonly transactionsCount: Scalars['Int']['output'];
479+
/** Type of the contact (intraledger, lnaddress, etc.). */
480+
readonly type: ContactType;
481+
};
482+
483+
export type ContactCreateInput = {
484+
readonly displayName?: InputMaybe<Scalars['ContactAlias']['input']>;
485+
readonly handle?: InputMaybe<Scalars['ContactHandle']['input']>;
486+
readonly type: ContactType;
487+
};
488+
489+
export type ContactPayload = {
490+
readonly __typename: 'ContactPayload';
491+
readonly contact?: Maybe<Contact>;
492+
readonly errors: ReadonlyArray<Error>;
493+
};
494+
495+
export const ContactType = {
496+
Intraledger: 'INTRALEDGER',
497+
Lnaddress: 'LNADDRESS'
498+
} as const;
499+
500+
export type ContactType = typeof ContactType[keyof typeof ContactType];
461501
export type Coordinates = {
462502
readonly __typename: 'Coordinates';
463503
readonly latitude: Scalars['Float']['output'];
@@ -997,6 +1037,7 @@ export type Mutation = {
9971037
readonly callbackEndpointDelete: SuccessPayload;
9981038
readonly captchaCreateChallenge: CaptchaCreateChallengePayload;
9991039
readonly captchaRequestAuthCode: SuccessPayload;
1040+
readonly contactCreate: ContactPayload;
10001041
readonly deviceNotificationTokenCreate: SuccessPayload;
10011042
readonly feedbackSubmit: SuccessPayload;
10021043
/**
@@ -1170,6 +1211,11 @@ export type MutationCaptchaRequestAuthCodeArgs = {
11701211
};
11711212

11721213

1214+
export type MutationContactCreateArgs = {
1215+
input: ContactCreateInput;
1216+
};
1217+
1218+
11731219
export type MutationDeviceNotificationTokenCreateArgs = {
11741220
input: DeviceNotificationTokenCreateInput;
11751221
};
@@ -2151,11 +2197,16 @@ export type UserContact = {
21512197
* Only the user can see the alias attached to their contact.
21522198
*/
21532199
readonly alias?: Maybe<Scalars['ContactAlias']['output']>;
2154-
readonly id: Scalars['Username']['output'];
2200+
/** Identifier of the contact (username or Lightning address). */
2201+
readonly handle: Scalars['ContactHandle']['output'];
2202+
readonly id: Scalars['ContactHandle']['output'];
21552203
/** Paginated list of transactions sent to/from this contact. */
21562204
readonly transactions?: Maybe<TransactionConnection>;
21572205
readonly transactionsCount: Scalars['Int']['output'];
2158-
/** Actual identifier of the contact. */
2206+
/**
2207+
* Actual identifier of the contact. Deprecated: use `handle` instead.
2208+
* @deprecated Use `handle` field; this will be removed in a future release.
2209+
*/
21592210
readonly username: Scalars['Username']['output'];
21602211
};
21612212

@@ -3558,7 +3609,14 @@ export type ResolversTypes = {
35583609
CentAmount: ResolverTypeWrapper<Scalars['CentAmount']['output']>;
35593610
CentAmountPayload: ResolverTypeWrapper<Omit<CentAmountPayload, 'errors'> & { errors: ReadonlyArray<ResolversTypes['Error']> }>;
35603611
ConsumerAccount: ResolverTypeWrapper<Omit<ConsumerAccount, 'callbackEndpoints' | 'invoices' | 'limits' | 'pendingIncomingTransactions' | 'transactions' | 'walletById' | 'wallets'> & { callbackEndpoints: ReadonlyArray<ResolversTypes['CallbackEndpoint']>, invoices?: Maybe<ResolversTypes['InvoiceConnection']>, limits: ResolversTypes['AccountLimits'], pendingIncomingTransactions: ReadonlyArray<ResolversTypes['Transaction']>, transactions?: Maybe<ResolversTypes['TransactionConnection']>, walletById: ResolversTypes['Wallet'], wallets: ReadonlyArray<ResolversTypes['Wallet']> }>;
3612+
Contact: ResolverTypeWrapper<Contact>;
35613613
ContactAlias: ResolverTypeWrapper<Scalars['ContactAlias']['output']>;
3614+
ContactCreateInput: ContactCreateInput;
3615+
ContactDisplayName: ResolverTypeWrapper<Scalars['ContactDisplayName']['output']>;
3616+
ContactHandle: ResolverTypeWrapper<Scalars['ContactHandle']['output']>;
3617+
ContactId: ResolverTypeWrapper<Scalars['ContactId']['output']>;
3618+
ContactPayload: ResolverTypeWrapper<Omit<ContactPayload, 'errors'> & { errors: ReadonlyArray<ResolversTypes['Error']> }>;
3619+
ContactType: ContactType;
35623620
Coordinates: ResolverTypeWrapper<Coordinates>;
35633621
Float: ResolverTypeWrapper<Scalars['Float']['output']>;
35643622
Country: ResolverTypeWrapper<Country>;
@@ -3790,7 +3848,13 @@ export type ResolversParentTypes = {
37903848
CentAmount: Scalars['CentAmount']['output'];
37913849
CentAmountPayload: Omit<CentAmountPayload, 'errors'> & { errors: ReadonlyArray<ResolversParentTypes['Error']> };
37923850
ConsumerAccount: Omit<ConsumerAccount, 'callbackEndpoints' | 'invoices' | 'limits' | 'pendingIncomingTransactions' | 'transactions' | 'walletById' | 'wallets'> & { callbackEndpoints: ReadonlyArray<ResolversParentTypes['CallbackEndpoint']>, invoices?: Maybe<ResolversParentTypes['InvoiceConnection']>, limits: ResolversParentTypes['AccountLimits'], pendingIncomingTransactions: ReadonlyArray<ResolversParentTypes['Transaction']>, transactions?: Maybe<ResolversParentTypes['TransactionConnection']>, walletById: ResolversParentTypes['Wallet'], wallets: ReadonlyArray<ResolversParentTypes['Wallet']> };
3851+
Contact: Contact;
37933852
ContactAlias: Scalars['ContactAlias']['output'];
3853+
ContactCreateInput: ContactCreateInput;
3854+
ContactDisplayName: Scalars['ContactDisplayName']['output'];
3855+
ContactHandle: Scalars['ContactHandle']['output'];
3856+
ContactId: Scalars['ContactId']['output'];
3857+
ContactPayload: Omit<ContactPayload, 'errors'> & { errors: ReadonlyArray<ResolversParentTypes['Error']> };
37943858
Coordinates: Coordinates;
37953859
Float: Scalars['Float']['output'];
37963860
Country: Country;
@@ -4203,10 +4267,38 @@ export type ConsumerAccountResolvers<ContextType = any, ParentType extends Resol
42034267
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
42044268
};
42054269

4270+
export type ContactResolvers<ContextType = any, ParentType extends ResolversParentTypes['Contact'] = ResolversParentTypes['Contact']> = {
4271+
createdAt?: Resolver<ResolversTypes['Timestamp'], ParentType, ContextType>;
4272+
displayName?: Resolver<Maybe<ResolversTypes['ContactDisplayName']>, ParentType, ContextType>;
4273+
handle?: Resolver<ResolversTypes['ContactHandle'], ParentType, ContextType>;
4274+
id?: Resolver<ResolversTypes['ContactId'], ParentType, ContextType>;
4275+
transactionsCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
4276+
type?: Resolver<ResolversTypes['ContactType'], ParentType, ContextType>;
4277+
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
4278+
};
4279+
42064280
export interface ContactAliasScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactAlias'], any> {
42074281
name: 'ContactAlias';
42084282
}
42094283

4284+
export interface ContactDisplayNameScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactDisplayName'], any> {
4285+
name: 'ContactDisplayName';
4286+
}
4287+
4288+
export interface ContactHandleScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactHandle'], any> {
4289+
name: 'ContactHandle';
4290+
}
4291+
4292+
export interface ContactIdScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ContactId'], any> {
4293+
name: 'ContactId';
4294+
}
4295+
4296+
export type ContactPayloadResolvers<ContextType = any, ParentType extends ResolversParentTypes['ContactPayload'] = ResolversParentTypes['ContactPayload']> = {
4297+
contact?: Resolver<Maybe<ResolversTypes['Contact']>, ParentType, ContextType>;
4298+
errors?: Resolver<ReadonlyArray<ResolversTypes['Error']>, ParentType, ContextType>;
4299+
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
4300+
};
4301+
42104302
export type CoordinatesResolvers<ContextType = any, ParentType extends ResolversParentTypes['Coordinates'] = ResolversParentTypes['Coordinates']> = {
42114303
latitude?: Resolver<ResolversTypes['Float'], ParentType, ContextType>;
42124304
longitude?: Resolver<ResolversTypes['Float'], ParentType, ContextType>;
@@ -4495,6 +4587,7 @@ export type MutationResolvers<ContextType = any, ParentType extends ResolversPar
44954587
callbackEndpointDelete?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationCallbackEndpointDeleteArgs, 'input'>>;
44964588
captchaCreateChallenge?: Resolver<ResolversTypes['CaptchaCreateChallengePayload'], ParentType, ContextType>;
44974589
captchaRequestAuthCode?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationCaptchaRequestAuthCodeArgs, 'input'>>;
4590+
contactCreate?: Resolver<ResolversTypes['ContactPayload'], ParentType, ContextType, RequireFields<MutationContactCreateArgs, 'input'>>;
44984591
deviceNotificationTokenCreate?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationDeviceNotificationTokenCreateArgs, 'input'>>;
44994592
feedbackSubmit?: Resolver<ResolversTypes['SuccessPayload'], ParentType, ContextType, RequireFields<MutationFeedbackSubmitArgs, 'input'>>;
45004593
intraLedgerPaymentSend?: Resolver<ResolversTypes['PaymentSendPayload'], ParentType, ContextType, RequireFields<MutationIntraLedgerPaymentSendArgs, 'input'>>;
@@ -4972,7 +5065,8 @@ export type UserResolvers<ContextType = any, ParentType extends ResolversParentT
49725065

49735066
export type UserContactResolvers<ContextType = any, ParentType extends ResolversParentTypes['UserContact'] = ResolversParentTypes['UserContact']> = {
49745067
alias?: Resolver<Maybe<ResolversTypes['ContactAlias']>, ParentType, ContextType>;
4975-
id?: Resolver<ResolversTypes['Username'], ParentType, ContextType>;
5068+
handle?: Resolver<ResolversTypes['ContactHandle'], ParentType, ContextType>;
5069+
id?: Resolver<ResolversTypes['ContactHandle'], ParentType, ContextType>;
49765070
transactions?: Resolver<Maybe<ResolversTypes['TransactionConnection']>, ParentType, ContextType, Partial<UserContactTransactionsArgs>>;
49775071
transactionsCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
49785072
username?: Resolver<ResolversTypes['Username'], ParentType, ContextType>;
@@ -5108,7 +5202,12 @@ export type Resolvers<ContextType = any> = {
51085202
CentAmount?: GraphQLScalarType;
51095203
CentAmountPayload?: CentAmountPayloadResolvers<ContextType>;
51105204
ConsumerAccount?: ConsumerAccountResolvers<ContextType>;
5205+
Contact?: ContactResolvers<ContextType>;
51115206
ContactAlias?: GraphQLScalarType;
5207+
ContactDisplayName?: GraphQLScalarType;
5208+
ContactHandle?: GraphQLScalarType;
5209+
ContactId?: GraphQLScalarType;
5210+
ContactPayload?: ContactPayloadResolvers<ContextType>;
51125211
Coordinates?: CoordinatesResolvers<ContextType>;
51135212
Country?: CountryResolvers<ContextType>;
51145213
CountryCode?: GraphQLScalarType;

apps/map/codegen.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,8 @@ generates:
6161
EndpointUrl: "string"
6262
Object: "string"
6363
NotificationCategory: "string"
64+
AccountId: "string"
65+
ContactId: "string"
66+
ContactHandle: "string"
67+
ContactType: "string"
68+
ContactDisplayName: "string"

0 commit comments

Comments
 (0)