(core) control the distribution of attachment metadata

Summary:
for users who don't automatically have deep rights
to the document, provide them with attachment metadata only
for rows they have access to. This is a little tricky to
do efficiently. We provide attachment metadata when an
individual table is fetched, rather than on initial document
load, so we don't block that load on a full document scan.
We provide attachment metadata to a client when we see that
we are shipping rows mentioning particular attachments,
without making any effort to keep track of the metadata they
already have.

Test Plan: updated tests

Reviewers: dsagal, jarek

Reviewed By: dsagal, jarek

Differential Revision: https://phab.getgrist.com/D3722
This commit is contained in:
Paul Fitzpatrick
2022-12-21 11:40:00 -05:00
parent 6dce083484
commit 472a9a186e
14 changed files with 429 additions and 169 deletions

View File

@@ -1,4 +1,6 @@
import { DocAction } from 'app/common/DocActions';
import { DocData } from 'app/common/DocData';
import { SchemaTypes } from 'app/common/schema';
import { FlexServer } from 'app/server/lib/FlexServer';
import axios from 'axios';
import pick = require('lodash/pick');
@@ -28,6 +30,7 @@ export class GristClient {
private _requestId: number = 0;
private _pending: Array<GristResponse|GristMessage> = [];
private _docData?: DocData; // accumulate tabular info like a real client.
private _consumer: () => void;
private _ignoreTrivialActions: boolean = false;
@@ -41,6 +44,17 @@ export class GristClient {
return;
}
this._pending.push(msg);
if (msg.data?.doc) {
this._docData = new DocData(() => {
throw new Error('no fetches');
}, msg.data.doc);
}
if (this._docData && msg.type === 'docUserAction') {
const docActions = msg.data?.docActions || [];
for (const docAction of docActions) {
this._docData.receiveAction(docAction);
}
}
if (this._consumer) { this._consumer(); }
};
}
@@ -65,6 +79,15 @@ export class GristClient {
return this._pending.length;
}
public get docData() {
if (!this._docData) { throw new Error('no DocData'); }
return this._docData;
}
public getMetaRecords(tableId: keyof SchemaTypes) {
return this.docData.getMetaTable(tableId).getRecords();
}
public async read(): Promise<any> {
for (;;) {
if (this._pending.length) {
@@ -97,6 +120,11 @@ export class GristClient {
}
}
public waitForServer() {
// send an arbitrary failing message and wait for response.
return this.send('ping');
}
// Helper to read the next docUserAction ignoring anything else (e.g. a duplicate clientConnect).
public async readDocUserAction(): Promise<DocAction[]> {
while (true) { // eslint-disable-line no-constant-condition