@ -646,6 +646,9 @@ export class DocWorkerApi {
// full document.
const dryRun = isAffirmative ( req . query . dryrun || req . query . dryRun ) ;
const dryRunSuccess = ( ) = > res . status ( 200 ) . json ( { dryRun : 'allowed' } ) ;
const filename = await this . _getDownloadFilename ( req ) ;
// We want to be have a way download broken docs that ActiveDoc may not be able
// to load. So, if the user owns the document, we unconditionally let them
// download.
@ -655,13 +658,13 @@ export class DocWorkerApi {
// We carefully avoid creating an ActiveDoc for the document being downloaded,
// in case it is broken in some way. It is convenient to be able to download
// broken files for diagnosis/recovery.
return await this . _docWorker . downloadDoc ( req , res , this . _docManager . storageManager );
return await this . _docWorker . downloadDoc ( req , res , this . _docManager . storageManager , filename );
} catch ( e ) {
if ( e . message && e . message . match ( /does not exist yet/ ) ) {
// The document has never been seen on file system / s3. It may be new, so
// we try again after having created an ActiveDoc for the document.
await this . _getActiveDoc ( req ) ;
return this . _docWorker . downloadDoc ( req , res , this . _docManager . storageManager );
return this . _docWorker . downloadDoc ( req , res , this . _docManager . storageManager , filename );
} else {
throw e ;
}
@ -674,7 +677,7 @@ export class DocWorkerApi {
throw new ApiError ( 'not authorized to download this document' , 403 ) ;
}
if ( dryRun ) { dryRunSuccess ( ) ; return ; }
return this . _docWorker . downloadDoc ( req , res , this . _docManager . storageManager );
return this . _docWorker . downloadDoc ( req , res , this . _docManager . storageManager , filename );
}
} ) ) ;
@ -1222,7 +1225,7 @@ export class DocWorkerApi {
this . _app . get ( '/api/docs/:docId/download/table-schema' , canView , withDoc ( async ( activeDoc , req , res ) = > {
const doc = await this . _dbManager . getDoc ( req ) ;
const options = this. _getDownloadOptions ( req , doc . name ) ;
const options = await this. _getDownloadOptions ( req ) ;
const tableSchema = await collectTableSchemaInFrictionlessFormat ( activeDoc , req , options ) ;
const apiPath = await this . _grist . getResourceUrl ( doc , 'api' ) ;
const query = new URLSearchParams ( req . query as { [ key : string ] : string } ) ;
@ -1241,18 +1244,14 @@ export class DocWorkerApi {
} ) ) ;
this . _app . get ( '/api/docs/:docId/download/csv' , canView , withDoc ( async ( activeDoc , req , res ) = > {
// Query DB for doc metadata to get the doc title.
const { name : docTitle } = await this . _dbManager . getDoc ( req ) ;
const options = this . _getDownloadOptions ( req , docTitle ) ;
const options = await this . _getDownloadOptions ( req ) ;
await downloadCSV ( activeDoc , req , res , options ) ;
} ) ) ;
this . _app . get ( '/api/docs/:docId/download/xlsx' , canView , withDoc ( async ( activeDoc , req , res ) = > {
// Query DB for doc metadata to get the doc title (to use as the filename).
const { name : docTitle } = await this . _dbManager . getDoc ( req ) ;
const options : DownloadOptions = ! _ . isEmpty ( req . query ) ? this . _getDownloadOptions ( req , docTitle ) : {
filename : docTitle ,
const options : DownloadOptions = ! _ . isEmpty ( req . query ) ? await this . _getDownloadOptions ( req ) : {
filename : await this . _getDownloadFilename ( req ) ,
tableId : '' ,
viewSectionId : undefined ,
filters : [ ] ,
@ -1734,11 +1733,24 @@ export class DocWorkerApi {
return docAuth . docId ! ;
}
private _getDownloadOptions ( req : Request , name : string ) : DownloadOptions {
private async _getDownloadFilename ( req : Request , tableId? : string ) : Promise < string > {
const addContext = process . env . GRIST_INCLUDE_CONTEXT_TO_DOWNLOAD_FILENAMES || false ;
// Query DB for doc metadata to get the doc data.
const doc = await this . _dbManager . getDoc ( req ) ;
const docTitle = doc . name ;
const prefix = addContext ? ` ${ doc . workspace ? . org ? . name } _ ${ doc . workspace ? . name } _ ` : '' ;
const sufix = tableId ? ( tableId === docTitle ? '' : ` _ ${ tableId } ` ) : '' ;
const filename = prefix + ( optStringParam ( req . query . title , 'title' ) || docTitle || 'document' ) + sufix ;
return filename ;
}
private async _getDownloadOptions ( req : Request ) : Promise < DownloadOptions > {
const params = parseExportParameters ( req ) ;
return {
. . . params ,
filename : name + ( params . tableId === name ? '' : '-' + params . tableId ) ,
filename : await this . _getDownloadFilename ( req , params . tableId ) ,
} ;
}