From ef5da42378025fca25df5611947a4e590fd1fa74 Mon Sep 17 00:00:00 2001 From: George Gevoian Date: Mon, 30 Aug 2021 13:06:40 -0700 Subject: [PATCH] (core) Update export CSV and Excel endpoints Summary: The endpoints for exporting CSV and Excel are now under /api/docs/:docId/ and are forwarded to a doc worker for export. The Share Menu has been updated to use the new endpoints. Test Plan: No new tests. Existing tests that verify endpoints work correctly. Reviewers: paulfitz Reviewed By: paulfitz Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D3007 --- app/client/components/GristDoc.ts | 9 +++++---- app/common/UserAPI.ts | 10 ++++++++++ app/gen-server/lib/DocApiForwarder.ts | 2 ++ app/server/lib/DocApi.ts | 5 +++++ app/server/lib/DocWorker.ts | 9 --------- app/server/lib/FlexServer.ts | 8 -------- app/server/serverMethods.ts | 18 +++--------------- 7 files changed, 25 insertions(+), 36 deletions(-) diff --git a/app/client/components/GristDoc.ts b/app/client/components/GristDoc.ts index 7aca22a1..d1c5cbea 100644 --- a/app/client/components/GristDoc.ts +++ b/app/client/components/GristDoc.ts @@ -626,11 +626,11 @@ export class GristDoc extends DisposableWithEvents { } public getXlsxLink() { + const baseUrl = this.docPageModel.appModel.api.getDocAPI(this.docId()).getGenerateXlsxUrl(); const params = { - ...this.docComm.getUrlParams(), title: this.docPageModel.currentDocTitle.get(), }; - return this.docComm.docUrl(`gen_xlsx`) + '?' + encodeQueryParams(params); + return baseUrl + '?' + encodeQueryParams(params); } public getCsvLink() { @@ -638,15 +638,16 @@ export class GristDoc extends DisposableWithEvents { colRef : field.colRef.peek(), filter : field.activeFilter.peek() })); + + const baseUrl = this.docPageModel.appModel.api.getDocAPI(this.docId()).getGenerateCsvUrl(); const params = { - ...this.docComm.getUrlParams(), title: this.docPageModel.currentDocTitle.get(), viewSection: this.viewModel.activeSectionId(), tableId: this.viewModel.activeSection().table().tableId(), activeSortSpec: JSON.stringify(this.viewModel.activeSection().activeSortSpec()), filters : JSON.stringify(filters), }; - return this.docComm.docUrl(`gen_csv`) + '?' + encodeQueryParams(params); + return baseUrl + '?' + encodeQueryParams(params); } public hasGranularAccessRules(): boolean { diff --git a/app/common/UserAPI.ts b/app/common/UserAPI.ts index d9732369..b05d5ab0 100644 --- a/app/common/UserAPI.ts +++ b/app/common/UserAPI.ts @@ -347,6 +347,8 @@ export interface DocAPI { // is HEAD, the result will contain a copy of any rows added or updated. compareVersion(leftHash: string, rightHash: string): Promise; getDownloadUrl(template?: boolean): string; + getGenerateXlsxUrl(): string; + getGenerateCsvUrl(): string; /** * Exports current document to the Google Drive as a spreadsheet file. To invoke this method, first * acquire "code" via Google Auth Endpoint (see ShareMenu.ts for an example). @@ -790,6 +792,14 @@ export class DocAPIImpl extends BaseAPI implements DocAPI { return this._url + `/download?template=${Number(template)}`; } + public getGenerateXlsxUrl() { + return this._url + '/gen-xlsx'; + } + + public getGenerateCsvUrl() { + return this._url + '/gen-csv'; + } + public async sendToDrive(code: string, title: string): Promise<{url: string}> { const url = new URL(`${this._url}/send-to-drive`); url.searchParams.append('title', title); diff --git a/app/gen-server/lib/DocApiForwarder.ts b/app/gen-server/lib/DocApiForwarder.ts index 6e7415c7..89b45754 100644 --- a/app/gen-server/lib/DocApiForwarder.ts +++ b/app/gen-server/lib/DocApiForwarder.ts @@ -42,6 +42,8 @@ export class DocApiForwarder { app.use('/api/docs/:docId/remove', withDoc); app.delete('/api/docs/:docId', withDoc); app.use('/api/docs/:docId/download', withDoc); + app.use('/api/docs/:docId/gen-csv', withDoc); + app.use('/api/docs/:docId/gen-xlsx', withDoc); app.use('/api/docs/:docId/send-to-drive', withDoc); app.use('/api/docs/:docId/fork', withDoc); app.use('/api/docs/:docId/create-fork', withDoc); diff --git a/app/server/lib/DocApi.ts b/app/server/lib/DocApi.ts index 1425af3f..779a1d5f 100644 --- a/app/server/lib/DocApi.ts +++ b/app/server/lib/DocApi.ts @@ -33,6 +33,7 @@ import { googleAuthTokenMiddleware } from "app/server/lib/GoogleAuth"; import * as _ from "lodash"; import {isRaisedException} from "app/common/gristTypes"; import {localeFromRequest} from "app/server/lib/ServerLocale"; +import { generateCSV, generateXLSX } from "app/server/serverMethods"; // Cap on the number of requests that can be outstanding on a single document via the // rest doc api. When this limit is exceeded, incoming requests receive an immediate @@ -565,6 +566,10 @@ export class DocWorkerApi { res.json(result); })); + this._app.get('/api/docs/:docId/gen-csv', canView, withDoc(generateCSV)); + + this._app.get('/api/docs/:docId/gen-xlsx', canView, withDoc(generateXLSX)); + this._app.get('/api/docs/:docId/send-to-drive', canView, decodeGoogleToken, withDoc(exportToDrive)); // Create a document. When an upload is included, it is imported as the initial diff --git a/app/server/lib/DocWorker.ts b/app/server/lib/DocWorker.ts index 5914f4b5..b7d89428 100644 --- a/app/server/lib/DocWorker.ts +++ b/app/server/lib/DocWorker.ts @@ -13,7 +13,6 @@ import {IDocStorageManager} from 'app/server/lib/IDocStorageManager'; import * as log from 'app/server/lib/log'; import {integerParam, optStringParam, stringParam} from 'app/server/lib/requestUtils'; import {OpenMode, quoteIdent, SQLiteDB} from 'app/server/lib/SQLiteDB'; -import {generateCSV, generateXLSX} from 'app/server/serverMethods'; import * as contentDisposition from 'content-disposition'; import * as express from 'express'; import * as fse from 'fs-extra'; @@ -30,14 +29,6 @@ export class DocWorker { this._comm = comm; } - public async getCSV(req: express.Request, res: express.Response): Promise { - await generateCSV(req, res, this._comm); - } - - public async getXLSX(req: express.Request, res: express.Response): Promise { - await generateXLSX(req, res, this._comm); - } - public async getAttachment(req: express.Request, res: express.Response): Promise { try { const docSession = this._getDocSession(stringParam(req.query.clientId), diff --git a/app/server/lib/FlexServer.ts b/app/server/lib/FlexServer.ts index d517cb58..37133709 100644 --- a/app/server/lib/FlexServer.ts +++ b/app/server/lib/FlexServer.ts @@ -1266,14 +1266,6 @@ export class FlexServer implements GristServer { // This doesn't check for doc access permissions because the request isn't tied to a document. addUploadRoute(this, this.app, this._trustOriginsMiddleware, ...basicMiddleware); - this.app.get('/gen_csv', ...docAccessMiddleware, expressWrap(async (req, res) => { - return this._docWorker.getCSV(req, res); - })); - - this.app.get('/gen_xlsx', ...docAccessMiddleware, expressWrap(async (req, res) => { - return this._docWorker.getXLSX(req, res); - })); - this.app.get('/attachment', ...docAccessMiddleware, expressWrap(async (req, res) => this._docWorker.getAttachment(req, res))); } diff --git a/app/server/serverMethods.ts b/app/server/serverMethods.ts index 80d481a8..0199e18e 100644 --- a/app/server/serverMethods.ts +++ b/app/server/serverMethods.ts @@ -1,13 +1,12 @@ -import * as Comm from 'app/server/lib/Comm'; import {parseExportFileName, parseExportParameters} from 'app/server/lib/Export'; import {makeCSV} from 'app/server/lib/ExportCSV'; import {makeXLSX} from 'app/server/lib/ExportXLSX'; import * as log from 'app/server/lib/log'; -import {integerParam, stringParam} from 'app/server/lib/requestUtils'; import * as contentDisposition from 'content-disposition'; import * as express from 'express'; +import {ActiveDoc} from 'app/server/lib/ActiveDoc'; -export async function generateCSV(req: express.Request, res: express.Response, comm: Comm) { +export async function generateCSV(activeDoc: ActiveDoc, req: express.Request, res: express.Response) { log.info('Generating .csv file...'); const { viewSectionId, @@ -15,12 +14,6 @@ export async function generateCSV(req: express.Request, res: express.Response, c sortOrder } = parseExportParameters(req); - const clientId = stringParam(req.query.clientId); - const docFD = integerParam(req.query.docFD); - const client = comm.getClient(clientId); - const docSession = client.getDocSession(docFD); - const activeDoc = docSession.activeDoc; - // Generate a decent name for the exported file. const name = parseExportFileName(activeDoc, req); try { @@ -40,13 +33,8 @@ export async function generateCSV(req: express.Request, res: express.Response, c } } -export async function generateXLSX(req: express.Request, res: express.Response, comm: Comm) { +export async function generateXLSX(activeDoc: ActiveDoc, req: express.Request, res: express.Response) { log.debug(`Generating .xlsx file`); - const clientId = stringParam(req.query.clientId); - const docFD = integerParam(req.query.docFD); - const client = comm.getClient(clientId); - const docSession = client.getDocSession(docFD); - const activeDoc = docSession.activeDoc; try { const data = await makeXLSX(activeDoc, req); res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');