diff --git a/app/server/lib/DocApi.ts b/app/server/lib/DocApi.ts index 1e0589e547..1216345841 100644 --- a/app/server/lib/DocApi.ts +++ b/app/server/lib/DocApi.ts @@ -1574,10 +1574,6 @@ export class DocWorkerApi { await this._getDownloadOptions(req) : { filename: await this._getDownloadFilename(req), - tableId: "", - viewSectionId: undefined, - filters: [], - sortOrder: [], header: "label", }; await downloadXLSX(activeDoc, req, res, options); diff --git a/app/server/lib/Export.ts b/app/server/lib/Export.ts index b99781a3aa..209adc61ba 100644 --- a/app/server/lib/Export.ts +++ b/app/server/lib/Export.ts @@ -17,7 +17,7 @@ import { BaseFormatter, createFullFormatterFromDocData } from "app/common/ValueF import { ActiveDoc } from "app/server/lib/ActiveDoc"; import { RequestWithLogin } from "app/server/lib/Authorizer"; import { docSessionFromRequest } from "app/server/lib/DocSession"; -import { optIntegerParam, optJsonParam, optStringParam, stringParam } from "app/server/lib/requestUtils"; +import { optIntegerParam, optJsonParam, optStringParam } from "app/server/lib/requestUtils"; import { ServerColumnGetters } from "app/server/lib/ServerColumnGetters"; import * as express from "express"; @@ -97,7 +97,7 @@ export type ExportHeader = "colId" | "label"; * Export parameters that identifies a section, filters, sort order. */ export interface ExportParameters { - tableId: string; // Value of '' is an instruction to export all tables. + tableId?: string; viewSectionId?: number; sortOrder?: number[]; filters?: Filter[]; @@ -116,7 +116,7 @@ export interface DownloadOptions extends ExportParameters { * Gets export parameters from a request. */ export function parseExportParameters(req: express.Request): ExportParameters { - const tableId = stringParam(req.query.tableId, "tableId"); + const tableId = optStringParam(req.query.tableId, "tableId"); const viewSectionId = optIntegerParam(req.query.viewSection, "viewSection"); const sortOrder = optJsonParam(req.query.activeSortSpec, []) as number[]; const filters: Filter[] = optJsonParam(req.query.filters, []); diff --git a/app/server/lib/ExportDSV.ts b/app/server/lib/ExportDSV.ts index 7bf35e8e58..93379e77db 100644 --- a/app/server/lib/ExportDSV.ts +++ b/app/server/lib/ExportDSV.ts @@ -31,12 +31,19 @@ export async function downloadDSV( const { filename, tableId, viewSectionId, filters, sortOrder, linkingFilter, delimiter, header } = options; const extension = getDSVFileExtension(delimiter); log.info(`Generating ${extension} file...`); - const data = viewSectionId ? - await makeDSVFromViewSection({ + let data; + if (viewSectionId) { + data = await makeDSVFromViewSection({ activeDoc, viewSectionId, sortOrder: sortOrder || null, filters: filters || null, linkingFilter: linkingFilter || null, header, delimiter, req, - }) : - await makeDSVFromTable({ activeDoc, tableId, header, delimiter, req }); + }); + } + else { + if (!tableId) { + throw new ApiError("tableId parameter is required", 400); + } + data = await makeDSVFromTable({ activeDoc, tableId, header, delimiter, req }); + } res.set("Content-Type", getDSVMimeType(delimiter)); res.setHeader("Content-Disposition", contentDisposition(filename + extension)); res.send(data); diff --git a/app/server/lib/ExportTableSchema.ts b/app/server/lib/ExportTableSchema.ts index 265c3c71d9..8a9c1374a0 100644 --- a/app/server/lib/ExportTableSchema.ts +++ b/app/server/lib/ExportTableSchema.ts @@ -43,6 +43,9 @@ export async function collectTableSchemaInFrictionlessFormat( if (!activeDoc.docData) { throw new Error("No docData in active document"); } + if (!tableId) { + throw new ApiError("tableId parameter is required", 400); + } // Look up the table to make a CSV from. const settings = activeDoc.docData.docSettings(); diff --git a/test/server/lib/DocApi.ts b/test/server/lib/DocApi.ts index 72ee0f400d..1381fa4503 100644 --- a/test/server/lib/DocApi.ts +++ b/test/server/lib/DocApi.ts @@ -3287,6 +3287,13 @@ function testDocApi(settings: { assert.notEqual(resp.data, null); }); + it("GET /docs/{did}/download/xlsx returns 200 if tableId is missing and header present", async function() { + const resp = await axios.get( + `${serverUrl}/api/docs/${docIds.TestDoc}/download/xlsx?header=label`, chimpy); + assert.equal(resp.status, 200); + assert.notEqual(resp.data, null); + }); + it("POST /workspaces/{wid}/import handles empty filenames", async function() { if (!process.env.TEST_REDIS_URL) { this.skip();