@@ -7,6 +7,7 @@ import { getXmtpContacts } from '@chainjet/tools/dist/messages'
77import { BadRequestException , Logger , UnauthorizedException , UseGuards , UseInterceptors } from '@nestjs/common'
88import { Args , Mutation , Resolver } from '@nestjs/graphql'
99import { Authorizer , AuthorizerInterceptor , InjectAuthorizer } from '@ptc-org/nestjs-query-graphql'
10+ import AWS from 'aws-sdk'
1011import { getAddress , isAddress } from 'ethers/lib/utils'
1112import { GraphQLBoolean , GraphQLString } from 'graphql'
1213import { ObjectId } from 'mongoose'
@@ -19,6 +20,13 @@ import { UserService } from '../../users/services/user.service'
1920import { Contact , CreateContactInput , UpdateContactInput } from '../entities/contact'
2021import { ContactService } from '../services/contact.service'
2122
23+ AWS . config . update ( {
24+ accessKeyId : process . env . AWS_ACCESS_KEY_ID ,
25+ secretAccessKey : process . env . AWS_SECRET_ACCESS_KEY ,
26+ region : 'us-east-2' ,
27+ } )
28+ const s3 = new AWS . S3 ( )
29+
2230@Resolver ( ( ) => Contact )
2331@UseGuards ( GraphqlGuard )
2432@UseInterceptors ( AuthorizerInterceptor ( Contact ) )
@@ -69,6 +77,85 @@ export class ContactResolver extends BaseResolver(Contact, {
6977 }
7078 }
7179
80+ @Mutation ( ( ) => GraphQLString )
81+ async generateContactsPresignedUrl (
82+ @UserId ( ) userId : ObjectId ,
83+ @Args ( { name : 'id' , type : ( ) => GraphQLString } ) id : string ,
84+ ) : Promise < string > {
85+ if ( ! userId ) {
86+ throw new UnauthorizedException ( 'Not logged in' )
87+ }
88+ const user = await this . userService . findOne ( { _id : userId } )
89+ if ( ! user ) {
90+ throw new BadRequestException ( 'User not found' )
91+ }
92+ const threeDays = new Date ( )
93+ threeDays . setDate ( threeDays . getDate ( ) + 3 )
94+ const params = {
95+ Bucket : 'chainjet-contacts' ,
96+ Fields : {
97+ key : `${ userId } /${ id } .txt` ,
98+ } ,
99+ Expires : 60 ,
100+ Metadata : {
101+ Expires : threeDays . toISOString ( ) ,
102+ } ,
103+ Conditions : [ [ 'content-length-range' , 0 , 52428800 ] ] , // up to 50MB
104+ }
105+ return new Promise ( ( resolve , reject ) => {
106+ s3 . createPresignedPost ( params , function ( err , data ) {
107+ if ( err ) {
108+ reject ( err )
109+ } else {
110+ resolve ( JSON . stringify ( data ) )
111+ }
112+ } )
113+ } )
114+ }
115+
116+ @Mutation ( ( ) => ResultPayload )
117+ async addContactsFile (
118+ @UserId ( ) userId : ObjectId ,
119+ @Args ( { name : 'id' , type : ( ) => GraphQLString } ) id : string ,
120+ @Args ( { name : 'tags' , type : ( ) => [ GraphQLString ] , nullable : true } ) tags ?: string [ ] ,
121+ @Args ( { name : 'limitToPlan' , type : ( ) => GraphQLBoolean , nullable : true } ) limitToPlan ?: boolean ,
122+ ) : Promise < ResultPayload > {
123+ if ( ! userId ) {
124+ throw new UnauthorizedException ( 'Not logged in' )
125+ }
126+ const user = await this . userService . findOne ( { _id : userId } )
127+ if ( ! user ) {
128+ throw new BadRequestException ( 'User not found' )
129+ }
130+
131+ const params = {
132+ Bucket : 'chainjet-contacts' ,
133+ Key : `${ userId } /${ id } .txt` ,
134+ }
135+
136+ let fileContent = ''
137+ try {
138+ const data = await s3 . getObject ( params ) . promise ( )
139+ fileContent = data . Body ?. toString ( 'utf-8' ) || ''
140+ } catch ( error ) {
141+ throw new Error ( `Failed to import the contacts: ${ error . message } ` )
142+ }
143+ const addresses = fileContent . split ( '\n' )
144+ if ( ! addresses || addresses . length === 0 ) {
145+ throw new BadRequestException ( 'Addresses cannot be empty' )
146+ }
147+ if ( addresses . some ( ( address ) => ! address || ! isAddress ( address ) ) ) {
148+ throw new BadRequestException (
149+ `Address ${ addresses . find ( ( address ) => ! address || ! isAddress ( address ) ) } is not valid` ,
150+ )
151+ }
152+ this . logger . log ( `Importing ${ addresses . length } addresses - user ${ user . id } ` )
153+ await this . contactService . addContacts ( addresses , user , tags , limitToPlan )
154+ return {
155+ success : true ,
156+ }
157+ }
158+
72159 @Mutation ( ( ) => ResultPayload )
73160 async importXmtpContacts (
74161 @UserId ( ) userId : ObjectId ,
0 commit comments