mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(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
This commit is contained in:
parent
5258fa649d
commit
ef5da42378
@ -626,11 +626,11 @@ export class GristDoc extends DisposableWithEvents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getXlsxLink() {
|
public getXlsxLink() {
|
||||||
|
const baseUrl = this.docPageModel.appModel.api.getDocAPI(this.docId()).getGenerateXlsxUrl();
|
||||||
const params = {
|
const params = {
|
||||||
...this.docComm.getUrlParams(),
|
|
||||||
title: this.docPageModel.currentDocTitle.get(),
|
title: this.docPageModel.currentDocTitle.get(),
|
||||||
};
|
};
|
||||||
return this.docComm.docUrl(`gen_xlsx`) + '?' + encodeQueryParams(params);
|
return baseUrl + '?' + encodeQueryParams(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCsvLink() {
|
public getCsvLink() {
|
||||||
@ -638,15 +638,16 @@ export class GristDoc extends DisposableWithEvents {
|
|||||||
colRef : field.colRef.peek(),
|
colRef : field.colRef.peek(),
|
||||||
filter : field.activeFilter.peek()
|
filter : field.activeFilter.peek()
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const baseUrl = this.docPageModel.appModel.api.getDocAPI(this.docId()).getGenerateCsvUrl();
|
||||||
const params = {
|
const params = {
|
||||||
...this.docComm.getUrlParams(),
|
|
||||||
title: this.docPageModel.currentDocTitle.get(),
|
title: this.docPageModel.currentDocTitle.get(),
|
||||||
viewSection: this.viewModel.activeSectionId(),
|
viewSection: this.viewModel.activeSectionId(),
|
||||||
tableId: this.viewModel.activeSection().table().tableId(),
|
tableId: this.viewModel.activeSection().table().tableId(),
|
||||||
activeSortSpec: JSON.stringify(this.viewModel.activeSection().activeSortSpec()),
|
activeSortSpec: JSON.stringify(this.viewModel.activeSection().activeSortSpec()),
|
||||||
filters : JSON.stringify(filters),
|
filters : JSON.stringify(filters),
|
||||||
};
|
};
|
||||||
return this.docComm.docUrl(`gen_csv`) + '?' + encodeQueryParams(params);
|
return baseUrl + '?' + encodeQueryParams(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasGranularAccessRules(): boolean {
|
public hasGranularAccessRules(): boolean {
|
||||||
|
@ -347,6 +347,8 @@ export interface DocAPI {
|
|||||||
// is HEAD, the result will contain a copy of any rows added or updated.
|
// is HEAD, the result will contain a copy of any rows added or updated.
|
||||||
compareVersion(leftHash: string, rightHash: string): Promise<DocStateComparison>;
|
compareVersion(leftHash: string, rightHash: string): Promise<DocStateComparison>;
|
||||||
getDownloadUrl(template?: boolean): string;
|
getDownloadUrl(template?: boolean): string;
|
||||||
|
getGenerateXlsxUrl(): string;
|
||||||
|
getGenerateCsvUrl(): string;
|
||||||
/**
|
/**
|
||||||
* Exports current document to the Google Drive as a spreadsheet file. To invoke this method, first
|
* 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).
|
* 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)}`;
|
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}> {
|
public async sendToDrive(code: string, title: string): Promise<{url: string}> {
|
||||||
const url = new URL(`${this._url}/send-to-drive`);
|
const url = new URL(`${this._url}/send-to-drive`);
|
||||||
url.searchParams.append('title', title);
|
url.searchParams.append('title', title);
|
||||||
|
@ -42,6 +42,8 @@ export class DocApiForwarder {
|
|||||||
app.use('/api/docs/:docId/remove', withDoc);
|
app.use('/api/docs/:docId/remove', withDoc);
|
||||||
app.delete('/api/docs/:docId', withDoc);
|
app.delete('/api/docs/:docId', withDoc);
|
||||||
app.use('/api/docs/:docId/download', 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/send-to-drive', withDoc);
|
||||||
app.use('/api/docs/:docId/fork', withDoc);
|
app.use('/api/docs/:docId/fork', withDoc);
|
||||||
app.use('/api/docs/:docId/create-fork', withDoc);
|
app.use('/api/docs/:docId/create-fork', withDoc);
|
||||||
|
@ -33,6 +33,7 @@ import { googleAuthTokenMiddleware } from "app/server/lib/GoogleAuth";
|
|||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import {isRaisedException} from "app/common/gristTypes";
|
import {isRaisedException} from "app/common/gristTypes";
|
||||||
import {localeFromRequest} from "app/server/lib/ServerLocale";
|
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
|
// 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
|
// rest doc api. When this limit is exceeded, incoming requests receive an immediate
|
||||||
@ -565,6 +566,10 @@ export class DocWorkerApi {
|
|||||||
res.json(result);
|
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));
|
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
|
// Create a document. When an upload is included, it is imported as the initial
|
||||||
|
@ -13,7 +13,6 @@ import {IDocStorageManager} from 'app/server/lib/IDocStorageManager';
|
|||||||
import * as log from 'app/server/lib/log';
|
import * as log from 'app/server/lib/log';
|
||||||
import {integerParam, optStringParam, stringParam} from 'app/server/lib/requestUtils';
|
import {integerParam, optStringParam, stringParam} from 'app/server/lib/requestUtils';
|
||||||
import {OpenMode, quoteIdent, SQLiteDB} from 'app/server/lib/SQLiteDB';
|
import {OpenMode, quoteIdent, SQLiteDB} from 'app/server/lib/SQLiteDB';
|
||||||
import {generateCSV, generateXLSX} from 'app/server/serverMethods';
|
|
||||||
import * as contentDisposition from 'content-disposition';
|
import * as contentDisposition from 'content-disposition';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import * as fse from 'fs-extra';
|
import * as fse from 'fs-extra';
|
||||||
@ -30,14 +29,6 @@ export class DocWorker {
|
|||||||
this._comm = comm;
|
this._comm = comm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getCSV(req: express.Request, res: express.Response): Promise<void> {
|
|
||||||
await generateCSV(req, res, this._comm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getXLSX(req: express.Request, res: express.Response): Promise<void> {
|
|
||||||
await generateXLSX(req, res, this._comm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getAttachment(req: express.Request, res: express.Response): Promise<void> {
|
public async getAttachment(req: express.Request, res: express.Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const docSession = this._getDocSession(stringParam(req.query.clientId),
|
const docSession = this._getDocSession(stringParam(req.query.clientId),
|
||||||
|
@ -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.
|
// This doesn't check for doc access permissions because the request isn't tied to a document.
|
||||||
addUploadRoute(this, this.app, this._trustOriginsMiddleware, ...basicMiddleware);
|
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,
|
this.app.get('/attachment', ...docAccessMiddleware,
|
||||||
expressWrap(async (req, res) => this._docWorker.getAttachment(req, res)));
|
expressWrap(async (req, res) => this._docWorker.getAttachment(req, res)));
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import * as Comm from 'app/server/lib/Comm';
|
|
||||||
import {parseExportFileName, parseExportParameters} from 'app/server/lib/Export';
|
import {parseExportFileName, parseExportParameters} from 'app/server/lib/Export';
|
||||||
import {makeCSV} from 'app/server/lib/ExportCSV';
|
import {makeCSV} from 'app/server/lib/ExportCSV';
|
||||||
import {makeXLSX} from 'app/server/lib/ExportXLSX';
|
import {makeXLSX} from 'app/server/lib/ExportXLSX';
|
||||||
import * as log from 'app/server/lib/log';
|
import * as log from 'app/server/lib/log';
|
||||||
import {integerParam, stringParam} from 'app/server/lib/requestUtils';
|
|
||||||
import * as contentDisposition from 'content-disposition';
|
import * as contentDisposition from 'content-disposition';
|
||||||
import * as express from 'express';
|
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...');
|
log.info('Generating .csv file...');
|
||||||
const {
|
const {
|
||||||
viewSectionId,
|
viewSectionId,
|
||||||
@ -15,12 +14,6 @@ export async function generateCSV(req: express.Request, res: express.Response, c
|
|||||||
sortOrder
|
sortOrder
|
||||||
} = parseExportParameters(req);
|
} = 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.
|
// Generate a decent name for the exported file.
|
||||||
const name = parseExportFileName(activeDoc, req);
|
const name = parseExportFileName(activeDoc, req);
|
||||||
try {
|
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`);
|
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 {
|
try {
|
||||||
const data = await makeXLSX(activeDoc, req);
|
const data = await makeXLSX(activeDoc, req);
|
||||||
res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
res.set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||||
|
Loading…
Reference in New Issue
Block a user