mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) uncheck FullCopy special when copying/forking a document
Summary: When a document has an exception to allow copies, unset that option on any copies of the document. Test Plan: added test Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2794
This commit is contained in:
parent
729774552f
commit
0e22716761
@ -15,6 +15,7 @@ import { docSessionFromRequest, makeExceptionalDocSession, OptDocSession } from
|
||||
import { DocWorker } from "app/server/lib/DocWorker";
|
||||
import { IDocWorkerMap } from "app/server/lib/DocWorkerMap";
|
||||
import { expressWrap } from 'app/server/lib/expressWrap';
|
||||
import { filterDocumentInPlace } from "app/server/lib/filterUtils";
|
||||
import { GristServer } from 'app/server/lib/GristServer';
|
||||
import { HashUtil } from 'app/server/lib/HashUtil';
|
||||
import { makeForkIds } from "app/server/lib/idUtils";
|
||||
@ -218,7 +219,8 @@ export class DocWorkerApi {
|
||||
const docId = stringParam(req.params.docId);
|
||||
const srcDocId = stringParam(req.body.srcDocId);
|
||||
if (srcDocId !== req.specialPermit?.otherDocId) { throw new Error('access denied'); }
|
||||
await this._docManager.storageManager.prepareFork(srcDocId, docId);
|
||||
const fname = await this._docManager.storageManager.prepareFork(srcDocId, docId);
|
||||
await filterDocumentInPlace(docSessionFromRequest(req), fname);
|
||||
res.json({srcDocId, docId});
|
||||
}));
|
||||
|
||||
|
@ -90,8 +90,10 @@ export class DocStorageManager implements IDocStorageManager {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public async prepareFork(srcDocName: string, destDocName: string): Promise<void> {
|
||||
// nothing to do
|
||||
public async prepareFork(srcDocName: string, destDocName: string): Promise<string> {
|
||||
// This is implemented only to support old tests.
|
||||
await fse.copy(this.getPath(srcDocName), this.getPath(destDocName));
|
||||
return this.getPath(destDocName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,8 @@ import {ActionHistoryImpl} from 'app/server/lib/ActionHistoryImpl';
|
||||
import {assertAccess, getOrSetDocAuth, getUserId, RequestWithLogin} from 'app/server/lib/Authorizer';
|
||||
import {Client} from 'app/server/lib/Client';
|
||||
import * as Comm from 'app/server/lib/Comm';
|
||||
import {DocSession} from 'app/server/lib/DocSession';
|
||||
import {DocSession, docSessionFromRequest} from 'app/server/lib/DocSession';
|
||||
import {filterDocumentInPlace} from 'app/server/lib/filterUtils';
|
||||
import {IDocStorageManager} from 'app/server/lib/IDocStorageManager';
|
||||
import * as log from 'app/server/lib/log';
|
||||
import {integerParam, optStringParam, stringParam} from 'app/server/lib/requestUtils';
|
||||
@ -75,6 +76,7 @@ export class DocWorker {
|
||||
// If template flag is on, remove data and history from the download.
|
||||
await removeData(tmpPath);
|
||||
}
|
||||
await filterDocumentInPlace(docSessionFromRequest(mreq), tmpPath);
|
||||
// NOTE: We may want to reconsider the mimeType used for Grist files.
|
||||
return res.type('application/x-sqlite3')
|
||||
.download(tmpPath, (optStringParam(req.query.title) || docTitle || 'document') + ".grist", async (err: any) => {
|
||||
|
@ -248,8 +248,9 @@ export class HostedStorageManager implements IDocStorageManager {
|
||||
* Initialize one document from another, associating the result with the current
|
||||
* worker.
|
||||
*/
|
||||
public async prepareFork(srcDocName: string, destDocName: string): Promise<void> {
|
||||
public async prepareFork(srcDocName: string, destDocName: string): Promise<string> {
|
||||
await this.prepareLocalDoc(destDocName, srcDocName);
|
||||
return this.getPath(destDocName);
|
||||
}
|
||||
|
||||
// Gets a copy of the document, eg. for downloading. Returns full file path.
|
||||
|
@ -12,7 +12,7 @@ export interface IDocStorageManager {
|
||||
// AsyncCreate[docName].
|
||||
prepareLocalDoc(docName: string): Promise<boolean>;
|
||||
prepareToCreateDoc(docName: string): Promise<void>;
|
||||
prepareFork(srcDocName: string, destDocName: string): Promise<void>;
|
||||
prepareFork(srcDocName: string, destDocName: string): Promise<string>; // Returns filename.
|
||||
|
||||
listDocs(): Promise<DocEntry[]>;
|
||||
deleteDoc(docName: string, deletePermanently?: boolean): Promise<void>;
|
||||
|
28
app/server/lib/filterUtils.ts
Normal file
28
app/server/lib/filterUtils.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { OpenMode, SQLiteDB } from 'app/server/lib/SQLiteDB';
|
||||
import { OptDocSession } from "app/server/lib/DocSession";
|
||||
|
||||
/**
|
||||
* Filter a Grist document when it is copied or downloaded. Changes made:
|
||||
* - Any FullCopies special rules are removed.
|
||||
* In the future, the changes could be made conditional on the user. This would
|
||||
* allow us for example to permit downloads of documents with row-level filters
|
||||
* in place.
|
||||
*/
|
||||
export async function filterDocumentInPlace(docSession: OptDocSession, filename: string) {
|
||||
// We ignore docSession for now, since no changes are user-dependent yet.
|
||||
// The change we need to make is simple, so we open the doc as a SQLite DB.
|
||||
// Note: the change is not entered in document history.
|
||||
const db = await SQLiteDB.openDBRaw(filename, OpenMode.OPEN_EXISTING);
|
||||
// Fetch ids of any special resources mentioning FullCopies (ideally there would be
|
||||
// at most one).
|
||||
const resourceIds = (await db.all("SELECT id FROM _grist_ACLResources " +
|
||||
"WHERE tableId='*SPECIAL' AND colIds='FullCopies'"))
|
||||
.map(row => row.id as number);
|
||||
if (resourceIds.length > 0) {
|
||||
// Remove any related rules.
|
||||
await db.run(`DELETE FROM _grist_ACLRules WHERE resource IN (${resourceIds})`);
|
||||
// Remove the resources.
|
||||
await db.run(`DELETE FROM _grist_ACLResources WHERE id IN (${resourceIds})`);
|
||||
}
|
||||
await db.close();
|
||||
}
|
Loading…
Reference in New Issue
Block a user