11import { BadRequestException , Inject , Injectable , NotFoundException , forwardRef } from '@nestjs/common' ;
2+ import PDFDocument from 'pdfkit' ;
3+ import { PdfUtil } from 'src/shared/utils/pdf.util' ;
24import { isIP } from 'class-validator' ;
35import * as IbanTools from 'ibantools' ;
46import { Config } from 'src/config/config' ;
@@ -109,6 +111,116 @@ export class SupportService {
109111 private readonly supportIssueService : SupportIssueService ,
110112 ) { }
111113
114+ async generateIpLogPdf ( userDataId : number ) : Promise < string > {
115+ const ipLogs = await this . ipLogService . getByUserDataId ( userDataId ) ;
116+
117+ return new Promise < string > ( ( resolve , reject ) => {
118+ try {
119+ const pdf = new PDFDocument ( { size : 'A4' , margin : 50 } ) ;
120+ const chunks : Buffer [ ] = [ ] ;
121+
122+ pdf . on ( 'data' , ( chunk ) => chunks . push ( chunk ) ) ;
123+ pdf . on ( 'end' , ( ) => resolve ( Buffer . concat ( chunks ) . toString ( 'base64' ) ) ) ;
124+
125+ PdfUtil . drawLogo ( pdf ) ;
126+
127+ // Header
128+ const marginX = 50 ;
129+ pdf . moveDown ( 2 ) ;
130+ pdf . fontSize ( 18 ) . font ( 'Helvetica-Bold' ) . fillColor ( '#072440' ) ;
131+ pdf . text ( 'IP Log Report' , marginX ) ;
132+ pdf . moveDown ( 0.5 ) ;
133+ pdf . fontSize ( 10 ) . font ( 'Helvetica' ) . fillColor ( '#333333' ) ;
134+ pdf . text ( `User Data ID: ${ userDataId } ` , marginX ) ;
135+ pdf . text ( `Date: ${ new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] } ` , marginX ) ;
136+ pdf . text ( `Total Entries: ${ ipLogs . length } ` , marginX ) ;
137+ pdf . moveDown ( 1 ) ;
138+
139+ // Table
140+ this . drawIpLogTable ( pdf , ipLogs ) ;
141+
142+ // Footer
143+ pdf . moveDown ( 2 ) ;
144+ pdf . fontSize ( 8 ) . font ( 'Helvetica' ) . fillColor ( '#999999' ) ;
145+ pdf . text ( `Generated by DFX - ${ new Date ( ) . toISOString ( ) } ` , marginX ) ;
146+
147+ pdf . end ( ) ;
148+ } catch ( e ) {
149+ reject ( e ) ;
150+ }
151+ } ) ;
152+ }
153+
154+ private drawIpLogTable ( pdf : InstanceType < typeof PDFDocument > , ipLogs : IpLog [ ] ) : void {
155+ const marginX = 50 ;
156+ const { width } = pdf . page ;
157+ const tableWidth = width - marginX * 2 ;
158+
159+ const cols = [
160+ { header : 'Date' , width : tableWidth * 0.2 } ,
161+ { header : 'IP' , width : tableWidth * 0.2 } ,
162+ { header : 'Country' , width : tableWidth * 0.12 } ,
163+ { header : 'Endpoint' , width : tableWidth * 0.36 } ,
164+ { header : 'Status' , width : tableWidth * 0.12 } ,
165+ ] ;
166+
167+ let y = pdf . y ;
168+
169+ // Headers
170+ pdf . fontSize ( 10 ) . font ( 'Helvetica-Bold' ) . fillColor ( '#072440' ) ;
171+ let x = marginX ;
172+ for ( const col of cols ) {
173+ pdf . text ( col . header , x , y , { width : col . width - 5 } ) ;
174+ x += col . width ;
175+ }
176+
177+ y += 18 ;
178+ pdf
179+ . moveTo ( marginX , y )
180+ . lineTo ( width - marginX , y )
181+ . stroke ( '#CCCCCC' ) ;
182+ y += 8 ;
183+
184+ // Rows
185+ pdf . fontSize ( 9 ) . font ( 'Helvetica' ) . fillColor ( '#333333' ) ;
186+
187+ if ( ipLogs . length === 0 ) {
188+ pdf . text ( 'No IP logs found' , marginX , y ) ;
189+ } else {
190+ for ( const log of ipLogs ) {
191+ if ( y > pdf . page . height - 80 ) {
192+ pdf . addPage ( ) ;
193+ y = 50 ;
194+ }
195+
196+ x = marginX ;
197+ const date = log . created ? new Date ( log . created ) . toISOString ( ) . replace ( 'T' , ' ' ) . substring ( 0 , 19 ) : '-' ;
198+ const endpoint = log . url ?. replace ( '/v1/' , '' ) ?? '-' ;
199+
200+ pdf . fillColor ( '#333333' ) ;
201+ pdf . text ( date , x , y , { width : cols [ 0 ] . width - 5 } ) ;
202+ x += cols [ 0 ] . width ;
203+ pdf . text ( log . ip ?? '-' , x , y , { width : cols [ 1 ] . width - 5 } ) ;
204+ x += cols [ 1 ] . width ;
205+ pdf . text ( log . country ?? '-' , x , y , { width : cols [ 2 ] . width - 5 } ) ;
206+ x += cols [ 2 ] . width ;
207+ pdf . text ( endpoint , x , y , { width : cols [ 3 ] . width - 5 } ) ;
208+ x += cols [ 3 ] . width ;
209+
210+ pdf . fillColor ( log . result ? '#28a745' : '#dc3545' ) ;
211+ pdf . text ( log . result ? 'Pass' : 'Fail' , x , y , { width : cols [ 4 ] . width - 5 } ) ;
212+
213+ y += 20 ;
214+ }
215+ }
216+
217+ pdf
218+ . moveTo ( marginX , y )
219+ . lineTo ( width - marginX , y )
220+ . stroke ( '#CCCCCC' ) ;
221+ pdf . y = y + 10 ;
222+ }
223+
112224 async getUserDataDetails ( id : number ) : Promise < UserDataSupportInfoDetails > {
113225 const userData = await this . userDataService . getUserData ( id , { wallet : true , bankDatas : true } ) ;
114226 if ( ! userData ) throw new NotFoundException ( `User not found` ) ;
@@ -328,7 +440,10 @@ export class SupportService {
328440 uid : tx . uid ,
329441 type : tx . type ,
330442 sourceType : tx . sourceType ,
443+ inputAmount : tx . buyCrypto ?. inputAmount ?? tx . buyFiat ?. inputAmount ,
444+ inputAsset : tx . buyCrypto ?. inputAsset ?? tx . buyFiat ?. inputAsset ,
331445 amountInChf : tx . amountInChf ,
446+ amountInEur : tx . buyCrypto ?. amountInEur ?? tx . buyFiat ?. amountInEur ,
332447 amlCheck : tx . amlCheck ,
333448 chargebackDate :
334449 tx . buyCrypto ?. chargebackDate ??
@@ -344,6 +459,7 @@ export class SupportService {
344459 return {
345460 id : user . id ,
346461 address : user . address ,
462+ ref : user . ref ,
347463 role : user . role ,
348464 status : user . status ,
349465 created : user . created ,
0 commit comments