@@ -39,7 +39,7 @@ module.exports = [
3939 * Add project attachment
4040 * In development mode we have to mock the ec2 file transfer and file service calls
4141 */
42- ( req , res , next ) => {
42+ async ( req , res , next ) => {
4343 const data = req . body ;
4444 // default values
4545 const projectId = req . params . projectId ;
@@ -53,64 +53,22 @@ module.exports = [
5353 // extract file name
5454 const fileName = Path . parse ( data . path ) . base ;
5555 // create file path
56- const path = _ . join ( [
56+ const attachmentPath = _ . join ( [
5757 config . get ( 'projectAttachmentPathPrefix' ) ,
5858 data . projectId ,
5959 config . get ( 'projectAttachmentPathPrefix' ) ,
6060 fileName ,
6161 ] , '/' ) ;
62- let newAttachment = null ;
6362
6463 const sourceBucket = data . s3Bucket ;
6564 const sourceKey = data . path ;
6665 const destBucket = config . get ( 'attachmentsS3Bucket' ) ;
67- const destKey = path ;
66+ const destKey = attachmentPath ;
6867
69- if ( data . type === ATTACHMENT_TYPES . LINK ) {
70- // We create the record in the db and return (i.e. no need to handle transferring file between S3 buckets)
71- Promise . resolve ( models . ProjectAttachment . create ( {
72- projectId,
73- allowedUsers,
74- createdBy : req . authUser . userId ,
75- updatedBy : req . authUser . userId ,
76- title : data . title ,
77- size : data . size ,
78- category : data . category || null ,
79- description : data . description ,
80- contentType : data . contentType ,
81- path : data . path ,
82- type : data . type ,
83- tags : data . tags ,
84- } ) ) . then ( ( _link ) => {
85- const link = _link . get ( { plain : true } ) ;
86- req . log . debug ( 'New Link Attachment record: ' , link ) ;
87-
88- // emit the Kafka event
89- util . sendResourceToKafkaBus (
90- req ,
91- EVENT . ROUTING_KEY . PROJECT_ATTACHMENT_ADDED ,
92- RESOURCES . ATTACHMENT ,
93- link ) ;
94-
95- res . status ( 201 ) . json ( link ) ;
96- return Promise . resolve ( ) ;
97- } )
98- . catch ( ( error ) => {
99- req . log . error ( 'Error adding link attachment' , error ) ;
100- const rerr = error ;
101- rerr . status = rerr . status || 500 ;
102- next ( rerr ) ;
103- } ) ;
104- } else {
105- // don't actually transfer file in development mode if file uploading is disabled, so we can test this endpoint
106- const fileTransferPromise = ( process . env . NODE_ENV !== 'development' || config . get ( 'enableFileUpload' ) === 'true' )
107- ? util . s3FileTransfer ( req , sourceBucket , sourceKey , destBucket , destKey )
108- : Promise . resolve ( ) ;
109-
110- fileTransferPromise . then ( ( ) => {
111- // file copied to final destination, create DB record
112- req . log . debug ( 'creating db file record' ) ;
113- return models . ProjectAttachment . create ( {
68+ try {
69+ if ( data . type === ATTACHMENT_TYPES . LINK ) {
70+ // Create the record and return immediately (no file transfer needed)
71+ const linkInstance = await models . ProjectAttachment . create ( {
11472 projectId,
11573 allowedUsers,
11674 createdBy : req . authUser . userId ,
@@ -120,60 +78,84 @@ module.exports = [
12078 category : data . category || null ,
12179 description : data . description ,
12280 contentType : data . contentType ,
123- path,
81+ path : data . path ,
12482 type : data . type ,
12583 tags : data . tags ,
12684 } ) ;
127- } ) . then ( ( _newAttachment ) => {
128- newAttachment = _newAttachment . get ( { plain : true } ) ;
129- req . log . debug ( 'New Attachment record: ' , newAttachment ) ;
130- if ( process . env . NODE_ENV !== 'development' || config . get ( 'enableFileUpload' ) === 'true' ) {
131- // retrieve download url for the response
132- req . log . debug ( 'retrieving download url' ) ;
133- return getDownloadUrl ( destBucket , path ) ;
134- }
135- return Promise . resolve ( ) ;
136- } ) . then ( ( url ) => {
137- if (
138- process . env . NODE_ENV !== 'development' ||
139- config . get ( 'enableFileUpload' ) === 'true'
140- ) {
141- req . log . debug ( 'Retreiving Presigned Url resp: ' , url ) ;
142- let response = _ . cloneDeep ( newAttachment ) ;
143- response = _ . omit ( response , [ 'path' , 'deletedAt' ] ) ;
144-
145- response . downloadUrl = url ;
146-
147- // emit the event
148- util . sendResourceToKafkaBus (
149- req ,
150- EVENT . ROUTING_KEY . PROJECT_ATTACHMENT_ADDED ,
151- RESOURCES . ATTACHMENT ,
152- newAttachment ,
153- ) ;
154- res . status ( 201 ) . json ( response ) ;
155- return Promise . resolve ( ) ;
156- }
157- let response = _ . cloneDeep ( newAttachment ) ;
158- response = _ . omit ( response , [ 'path' , 'deletedAt' ] ) ;
159- // only in development mode
160- response . downloadUrl = path ;
161- // emit the event
85+ const link = linkInstance . get ( { plain : true } ) ;
86+ req . log . debug ( 'New Link Attachment record: ' , link ) ;
87+
16288 util . sendResourceToKafkaBus (
16389 req ,
16490 EVENT . ROUTING_KEY . PROJECT_ATTACHMENT_ADDED ,
16591 RESOURCES . ATTACHMENT ,
166- newAttachment ) ;
167-
168- res . status ( 201 ) . json ( response ) ;
169- return Promise . resolve ( ) ;
170- } )
171- . catch ( ( error ) => {
172- req . log . error ( 'Error adding file attachment' , error ) ;
173- const rerr = error ;
174- rerr . status = rerr . status || 500 ;
175- next ( rerr ) ;
176- } ) ;
92+ link ,
93+ ) ;
94+
95+ res . status ( 201 ) . json ( link ) ;
96+ return ;
97+ }
98+
99+ const shouldTransfer = process . env . NODE_ENV !== 'development' || config . get ( 'enableFileUpload' ) === 'true' ;
100+ const downloadUrlPromise = shouldTransfer
101+ ? getDownloadUrl ( destBucket , destKey )
102+ : Promise . resolve ( destKey ) ;
103+
104+ req . log . debug ( 'creating db file record' ) ;
105+ const attachmentInstance = await models . ProjectAttachment . create ( {
106+ projectId,
107+ allowedUsers,
108+ createdBy : req . authUser . userId ,
109+ updatedBy : req . authUser . userId ,
110+ title : data . title ,
111+ size : data . size ,
112+ category : data . category || null ,
113+ description : data . description ,
114+ contentType : data . contentType ,
115+ path : destKey ,
116+ type : data . type ,
117+ tags : data . tags ,
118+ } ) ;
119+
120+ const newAttachment = attachmentInstance . get ( { plain : true } ) ;
121+ req . log . debug ( 'New Attachment record: ' , newAttachment ) ;
122+
123+ const downloadUrl = await downloadUrlPromise ;
124+ req . log . debug ( 'Retrieved presigned url for new attachment' ) ;
125+
126+ let response = _ . cloneDeep ( newAttachment ) ;
127+ response = _ . omit ( response , [ 'path' , 'deletedAt' ] ) ;
128+ response . downloadUrl = downloadUrl ;
129+
130+ util . sendResourceToKafkaBus (
131+ req ,
132+ EVENT . ROUTING_KEY . PROJECT_ATTACHMENT_ADDED ,
133+ RESOURCES . ATTACHMENT ,
134+ newAttachment ,
135+ ) ;
136+
137+ res . status ( 201 ) . json ( response ) ;
138+
139+ if ( shouldTransfer ) {
140+ util . s3FileTransfer ( req , sourceBucket , sourceKey , destBucket , destKey )
141+ . then ( ( ) => {
142+ req . log . debug ( 'File attachment copied asynchronously' , { attachmentId : newAttachment . id } ) ;
143+ } )
144+ . catch ( ( error ) => {
145+ req . log . error ( 'Async S3 file transfer failed' , {
146+ error : error . message ,
147+ stack : error . stack ,
148+ attachmentId : newAttachment . id ,
149+ source : `${ sourceBucket } /${ sourceKey } ` ,
150+ destination : `${ destBucket } /${ destKey } ` ,
151+ } ) ;
152+ } ) ;
153+ }
154+ } catch ( error ) {
155+ req . log . error ( 'Error adding attachment' , error ) ;
156+ const rerr = error ;
157+ rerr . status = rerr . status || 500 ;
158+ next ( rerr ) ;
177159 }
178160 } ,
179161] ;
0 commit comments