@@ -7,32 +7,30 @@ import tmp from 'tmp';
77import fs from 'fs' ;
88
99const DefaultExportExportProgressCollectionName = "_ExportProgress" ;
10+ const relationSchema = { fields : { relatedId : { type : 'String' } , owningId : { type : 'String' } } } ;
1011
1112export class ExportRouter extends PromiseRouter {
1213
13- handleExportProgress ( req ) {
1414
15- const databaseController = req . config . database ;
1615
17- let query = {
18- masterKey : req . info . masterKey ,
19- applicationId : req . info . appId
20- } ;
16+ exportClassPage ( req , name , jsonFileStream , where , skip , limit ) {
2117
22- return databaseController . find ( DefaultExportExportProgressCollectionName , query )
23- . then ( ( response ) => {
24- return { response } ;
25- } ) ;
26- }
18+ const databaseController = req . config . database ;
2719
28- handleExportPage ( req , name , jsonFileStream , where , skip , limit ) {
2920 let options = {
3021 skip,
3122 limit
3223 } ;
3324
34- return rest . find ( req . config , req . auth , name , where , options )
25+ let findPromise = name . indexOf ( '_Join' ) === 0 ?
26+ databaseController . adapter . find ( name , relationSchema , where , options )
27+ : rest . find ( req . config , req . auth , name , where , options ) ;
28+
29+ return findPromise
3530 . then ( ( data ) => {
31+ if ( Array . isArray ( data ) ) {
32+ data = { results : data } ;
33+ }
3634
3735 if ( skip && data . results . length ) {
3836 jsonFileStream . write ( ',\n' ) ;
@@ -42,35 +40,26 @@ export class ExportRouter extends PromiseRouter {
4240 } ) ;
4341 }
4442
45- handleExport ( req ) {
43+ exportClass ( req , data ) {
4644
47- const databaseController = req . config . database ;
48- let data = req . body ;
4945
46+ const databaseController = req . config . database ;
5047 let tmpJsonFile = tmp . fileSync ( ) ;
5148 let jsonFileStream = fs . createWriteStream ( tmpJsonFile . name ) ;
5249
5350 jsonFileStream . write ( '{\n"results" : [\n' ) ;
5451
55- let exportProgress = {
56- id : data . name ,
57- masterKey : req . info . masterKey ,
58- applicationId : req . info . appId
59- } ;
60-
52+ let findPromise = data . name . indexOf ( '_Join' ) === 0 ?
53+ databaseController . adapter . count ( data . name , relationSchema , data . where )
54+ : rest . find ( req . config , req . auth , data . name , data . where , { count : true , limit : 0 } ) ;
6155
62- let emailControllerAdapter = req . config . emailControllerAdapter ;
63-
64- if ( ! emailControllerAdapter ) {
65- return Promise . reject ( new Error ( 'You have to setup a Mail Adapter.' ) ) ;
66- }
67-
68- databaseController . create ( DefaultExportExportProgressCollectionName , exportProgress )
69- . then ( ( ) => {
70- return rest . find ( req . config , req . auth , data . name , data . where , { count : true , limit : 0 } ) ;
71- } )
56+ return findPromise
7257 . then ( ( result ) => {
7358
59+ if ( Number . isInteger ( result ) ) {
60+ result = { count : result } ;
61+ }
62+
7463 let i = 0 ;
7564 let pageLimit = 1000 ;
7665 let promise = Promise . resolve ( ) ;
@@ -80,7 +69,7 @@ export class ExportRouter extends PromiseRouter {
8069
8170 let skip = i ;
8271 promise = promise . then ( ( ) => {
83- return this . handleExportPage ( req , data . name , jsonFileStream , data . where , skip , pageLimit ) ;
72+ return this . exportClassPage ( req , data . name , jsonFileStream , data . where , skip , pageLimit ) ;
8473 } ) ;
8574 }
8675
@@ -93,54 +82,118 @@ export class ExportRouter extends PromiseRouter {
9382 return new Promise ( ( resolve , reject ) => {
9483
9584 jsonFileStream . on ( 'close' , ( ) => {
85+ tmpJsonFile . _name = `${ data . name . replace ( ':' , '/' ) } .json` ;
86+
87+ resolve ( tmpJsonFile ) ;
88+ } ) ;
89+ } )
90+ } ) ;
91+ }
92+
93+ handleExportProgress ( req ) {
94+
95+ const databaseController = req . config . database ;
96+
97+ let query = {
98+ masterKey : req . info . masterKey ,
99+ applicationId : req . info . appId
100+ } ;
96101
97- let tmpZipFile = tmp . fileSync ( ) ;
98- let tmpZipStream = fs . createWriteStream ( tmpZipFile . name ) ;
102+ return databaseController . find ( DefaultExportExportProgressCollectionName , query )
103+ . then ( ( response ) => {
104+ return { response } ;
105+ } ) ;
106+ }
99107
100- let zip = archiver ( 'zip' , { store : true } ) ;
101- zip . pipe ( tmpZipStream ) ;
102- zip . append ( fs . readFileSync ( tmpJsonFile . name ) , { name : `${ data . name } .json` } ) ;
103- zip . finalize ( ) ;
108+ handleExport ( req ) {
104109
105- tmpJsonFile . removeCallback ( ) ;
110+ const databaseController = req . config . database ;
106111
107- tmpZipStream . on ( 'close' , ( ) => {
112+ let emailControllerAdapter = req . config . emailControllerAdapter ;
108113
109- let buf = fs . readFileSync ( tmpZipFile . name ) ;
110- tmpZipFile . removeCallback ( ) ;
111- resolve ( buf ) ;
114+ if ( ! emailControllerAdapter ) {
115+ return Promise . reject ( new Error ( 'You have to setup a Mail Adapter.' ) ) ;
116+ }
112117
113- } ) ;
118+ let exportProgress = {
119+ id : req . body . name ,
120+ masterKey : req . info . masterKey ,
121+ applicationId : req . info . appId
122+ } ;
114123
115- } ) ;
116- } )
117- } )
118- . then ( ( zippedFile ) => {
119- const filesController = req . config . filesController ;
120- return filesController . createFile ( req . config , data . name , zippedFile , 'application/zip' ) ;
121- } )
122- . then ( ( fileData ) => {
123-
124- return emailControllerAdapter . sendMail ( {
125- text : `We have successfully exported your data from the class ${ data . name } .\n
126- Please download from ${ fileData . url } ` ,
127- link : fileData . url ,
128- to : req . body . feedbackEmail ,
129- subject : 'Export completed'
124+ databaseController . create ( DefaultExportExportProgressCollectionName , exportProgress )
125+ . then ( ( ) => {
126+ return databaseController . loadSchema ( { clearCache : true } ) ;
127+ } )
128+ . then ( schemaController => schemaController . getOneSchema ( req . body . name , true ) )
129+ . then ( ( schema ) => {
130+ let classNames = [ req . body . name ] ;
131+ Object . keys ( schema . fields ) . forEach ( ( fieldName ) => {
132+ let field = schema . fields [ fieldName ] ;
133+
134+ if ( field . type === 'Relation' ) {
135+ classNames . push ( `_Join:${ fieldName } :${ req . body . name } ` ) ;
136+ }
137+ } ) ;
138+
139+ let promisses = classNames . map ( ( name ) => {
140+ return this . exportClass ( req , { name } ) ;
141+ } ) ;
142+
143+ return Promise . all ( promisses )
144+ } )
145+ . then ( ( jsonFiles ) => {
146+
147+ return new Promise ( ( resolve ) => {
148+ let tmpZipFile = tmp . fileSync ( ) ;
149+ let tmpZipStream = fs . createWriteStream ( tmpZipFile . name ) ;
150+
151+ let zip = archiver ( 'zip' , { store : true } ) ;
152+ zip . pipe ( tmpZipStream ) ;
153+
154+ jsonFiles . forEach ( tmpJsonFile => {
155+ zip . append ( fs . readFileSync ( tmpJsonFile . name ) , { name : tmpJsonFile . _name } ) ;
156+ tmpJsonFile . removeCallback ( ) ;
130157 } ) ;
131- } )
132- . catch ( ( error ) => {
133- return emailControllerAdapter . sendMail ( {
134- text : `We could not export your data to the class ${ data . name } . Error: ${ error } ` ,
135- to : req . body . feedbackEmail ,
136- subject : 'Export failed'
158+
159+ zip . finalize ( ) ;
160+
161+ tmpZipStream . on ( 'close' , ( ) => {
162+
163+ let buf = fs . readFileSync ( tmpZipFile . name ) ;
164+ tmpZipFile . removeCallback ( ) ;
165+ resolve ( buf ) ;
166+
137167 } ) ;
138- } )
139- . then ( ( ) => {
140- return databaseController . destroy ( DefaultExportExportProgressCollectionName , exportProgress ) ;
141168 } ) ;
142169
143- return Promise . resolve ( { response : 'We are exporting your data. You will be notified by e-mail once it is completed.' } ) ;
170+ } )
171+ . then ( ( zippedFile ) => {
172+ const filesController = req . config . filesController ;
173+ return filesController . createFile ( req . config , req . body . name , zippedFile , 'application/zip' ) ;
174+ } )
175+ . then ( ( fileData ) => {
176+
177+ return emailControllerAdapter . sendMail ( {
178+ text : `We have successfully exported your data from the class ${ req . body . name } .\n
179+ Please download from ${ fileData . url } ` ,
180+ link : fileData . url ,
181+ to : req . body . feedbackEmail ,
182+ subject : 'Export completed'
183+ } ) ;
184+ } )
185+ . catch ( ( error ) => {
186+ return emailControllerAdapter . sendMail ( {
187+ text : `We could not export your data to the class ${ data . name } . Error: ${ error } ` ,
188+ to : req . body . feedbackEmail ,
189+ subject : 'Export failed'
190+ } ) ;
191+ } )
192+ . then ( ( ) => {
193+ return databaseController . destroy ( DefaultExportExportProgressCollectionName , exportProgress ) ;
194+ } ) ;
195+
196+ return Promise . resolve ( { response : 'We are exporting your data. You will be notified by e-mail once it is completed.' } ) ;
144197 }
145198
146199 mountRoutes ( ) {
0 commit comments