mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
51ff72c15e
Summary: Building: - Builds no longer wait for tsc for either client, server, or test targets. All use esbuild which is very fast. - Build still runs tsc, but only to report errors. This may be turned off with `SKIP_TSC=1` env var. - Grist-core continues to build using tsc. - Esbuild requires ES6 module semantics. Typescript's esModuleInterop is turned on, so that tsc accepts and enforces correct usage. - Client-side code is watched and bundled by webpack as before (using esbuild-loader) Code changes: - Imports must now follow ES6 semantics: `import * as X from ...` produces a module object; to import functions or class instances, use `import X from ...`. - Everything is now built with isolatedModules flag. Some exports were updated for it. Packages: - Upgraded browserify dependency, and related packages (used for the distribution-building step). - Building the distribution now uses esbuild's minification. babel-minify is no longer used. Test Plan: Should have no behavior changes, existing tests should pass, and docker image should build too. Reviewers: georgegevoian Reviewed By: georgegevoian Subscribers: alexmojaki Differential Revision: https://phab.getgrist.com/D3506
96 lines
3.1 KiB
TypeScript
96 lines
3.1 KiB
TypeScript
import {drive} from '@googleapis/drive';
|
|
import {Readable} from 'form-data';
|
|
import {GaxiosError, GaxiosPromise} from 'gaxios';
|
|
import {FetchError, Response as FetchResponse, Headers} from 'node-fetch';
|
|
import {getGoogleAuth} from "app/server/lib/GoogleAuth";
|
|
import contentDisposition from 'content-disposition';
|
|
|
|
const
|
|
SPREADSHEETS_MIMETYPE = 'application/vnd.google-apps.spreadsheet',
|
|
XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
|
|
export async function downloadFromGDrive(url: string, code?: string) {
|
|
const fileId = fileIdFromUrl(url);
|
|
const key = process.env.GOOGLE_API_KEY;
|
|
if (!key) {
|
|
throw new Error("Can't download file from Google Drive. Api key is not configured");
|
|
}
|
|
if (!fileId) {
|
|
throw new Error(`Can't download from ${url}. Url is not valid`);
|
|
}
|
|
const googleDrive = await initDriveApi(code);
|
|
const fileRes = await googleDrive.files.get({
|
|
key,
|
|
fileId
|
|
});
|
|
if (fileRes.data.mimeType === SPREADSHEETS_MIMETYPE) {
|
|
let filename = fileRes.data.name;
|
|
if (filename && !filename.includes(".")) {
|
|
filename = `${filename}.xlsx`;
|
|
}
|
|
return await asFetchResponse(googleDrive.files.export(
|
|
{key, fileId, alt: 'media', mimeType: XLSX_MIMETYPE},
|
|
{responseType: 'stream'}
|
|
), filename);
|
|
} else {
|
|
return await asFetchResponse(googleDrive.files.get(
|
|
{key, fileId, alt: 'media'},
|
|
{responseType: 'stream'}
|
|
), fileRes.data.name);
|
|
}
|
|
}
|
|
|
|
async function initDriveApi(code?: string) {
|
|
if (code) {
|
|
// Create drive with access token.
|
|
const auth = getGoogleAuth();
|
|
const token = await auth.getToken(code);
|
|
if (token.tokens) {
|
|
auth.setCredentials(token.tokens);
|
|
}
|
|
return drive({version: 'v3', auth: code ? auth : undefined});
|
|
}
|
|
// Create drive for public access.
|
|
return drive({version: 'v3'});
|
|
}
|
|
|
|
async function asFetchResponse(req: GaxiosPromise<Readable>, filename?: string | null) {
|
|
try {
|
|
const res = await req;
|
|
const headers = new Headers(res.headers);
|
|
if (filename) {
|
|
headers.set("content-disposition", contentDisposition(filename));
|
|
}
|
|
return new FetchResponse(res.data, {
|
|
headers,
|
|
status: res.status,
|
|
statusText: res.statusText
|
|
});
|
|
} catch (err) {
|
|
const error: GaxiosError<Readable> = err;
|
|
if (!error.response) {
|
|
// Fetch throws exception on network error.
|
|
// https://github.com/node-fetch/node-fetch/blob/master/docs/ERROR-HANDLING.md
|
|
throw new FetchError(error.message, "system", error.code || "unknown");
|
|
} else {
|
|
// Fetch returns failure response on http error
|
|
const resInit = error.response ? {
|
|
status: error.response.status,
|
|
headers: new Headers(error.response.headers),
|
|
statusText: error.response.statusText
|
|
} : undefined;
|
|
return new FetchResponse(error.response.data, resInit);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function isDriveUrl(url: string) {
|
|
return !!fileIdFromUrl(url);
|
|
}
|
|
|
|
function fileIdFromUrl(url: string) {
|
|
if (!url) { return null; }
|
|
const match = /^https:\/\/(docs|drive).google.com\/(spreadsheets|file)\/d\/([^/?]*)/i.exec(url);
|
|
return match ? match[3] : null;
|
|
}
|