mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Add documentCreated telemetry event
Summary: The event is triggered whenever a document is created, imported, or duplicated. Test Plan: Tested manually. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D4035
This commit is contained in:
@@ -17,6 +17,7 @@ import {SchemaTypes} from "app/common/schema";
|
||||
import {SortFunc} from 'app/common/SortFunc';
|
||||
import {Sort} from 'app/common/SortSpec';
|
||||
import {MetaRowRecord} from 'app/common/TableData';
|
||||
import {TelemetryMetadataByLevel} from "app/common/Telemetry";
|
||||
import {WebhookFields} from "app/common/Triggers";
|
||||
import TriggersTI from 'app/common/Triggers-ti';
|
||||
import {DocReplacementOptions, DocState, DocStateComparison, DocStates, NEW_DOCUMENT_CODE} from 'app/common/UserAPI';
|
||||
@@ -1150,6 +1151,7 @@ export class DocWorkerApi {
|
||||
// endpoint is handled only by DocWorker, so is handled here. (Note: this does not handle
|
||||
// actual file uploads, so no worries here about large request bodies.)
|
||||
this._app.post('/api/workspaces/:wid/import', expressWrap(async (req, res) => {
|
||||
const mreq = req as RequestWithLogin;
|
||||
const userId = getUserId(req);
|
||||
const wsId = integerParam(req.params.wid, 'wid');
|
||||
const uploadId = integerParam(req.body.uploadId, 'uploadId');
|
||||
@@ -1158,6 +1160,16 @@ export class DocWorkerApi {
|
||||
uploadId,
|
||||
workspaceId: wsId,
|
||||
browserSettings: req.body.browserSettings,
|
||||
telemetryMetadata: {
|
||||
limited: {
|
||||
isImport: true,
|
||||
sourceDocIdDigest: undefined,
|
||||
},
|
||||
full: {
|
||||
userId: mreq.userId,
|
||||
altSessionId: mreq.altSessionId,
|
||||
},
|
||||
},
|
||||
});
|
||||
res.json(result);
|
||||
}));
|
||||
@@ -1243,6 +1255,7 @@ export class DocWorkerApi {
|
||||
* TODO: unify this with the other document creation and import endpoints.
|
||||
*/
|
||||
this._app.post('/api/docs', checkAnonymousCreation, expressWrap(async (req, res) => {
|
||||
const mreq = req as RequestWithLogin;
|
||||
const userId = getUserId(req);
|
||||
|
||||
let uploadId: number|undefined;
|
||||
@@ -1279,6 +1292,16 @@ export class DocWorkerApi {
|
||||
documentName: optStringParam(parameters.documentName, 'documentName'),
|
||||
workspaceId,
|
||||
browserSettings,
|
||||
telemetryMetadata: {
|
||||
limited: {
|
||||
isImport: true,
|
||||
sourceDocIdDigest: undefined,
|
||||
},
|
||||
full: {
|
||||
userId: mreq.userId,
|
||||
altSessionId: mreq.altSessionId,
|
||||
},
|
||||
},
|
||||
});
|
||||
docId = result.id;
|
||||
} else if (workspaceId !== undefined) {
|
||||
@@ -1304,6 +1327,7 @@ export class DocWorkerApi {
|
||||
documentName: string,
|
||||
asTemplate?: boolean,
|
||||
}): Promise<string> {
|
||||
const mreq = req as RequestWithLogin;
|
||||
const {userId, sourceDocumentId, workspaceId, documentName, asTemplate = false} = options;
|
||||
|
||||
// First, upload a copy of the document.
|
||||
@@ -1326,6 +1350,16 @@ export class DocWorkerApi {
|
||||
uploadId: uploadResult.uploadId,
|
||||
documentName,
|
||||
workspaceId,
|
||||
telemetryMetadata: {
|
||||
limited: {
|
||||
isImport: false,
|
||||
sourceDocIdDigest: sourceDocumentId,
|
||||
},
|
||||
full: {
|
||||
userId: mreq.userId,
|
||||
altSessionId: mreq.altSessionId,
|
||||
},
|
||||
},
|
||||
});
|
||||
return result.id;
|
||||
}
|
||||
@@ -1341,7 +1375,15 @@ export class DocWorkerApi {
|
||||
if (status !== 200) {
|
||||
throw new ApiError(errMessage || 'unable to create document', status);
|
||||
}
|
||||
|
||||
this._logDocumentCreatedTelemetryEvent(req, {
|
||||
limited: {
|
||||
docIdDigest: data!,
|
||||
sourceDocIdDigest: undefined,
|
||||
isImport: false,
|
||||
fileType: undefined,
|
||||
isSaved: true,
|
||||
},
|
||||
});
|
||||
return data!;
|
||||
}
|
||||
|
||||
@@ -1365,9 +1407,29 @@ export class DocWorkerApi {
|
||||
}),
|
||||
docId
|
||||
);
|
||||
this._logDocumentCreatedTelemetryEvent(req, {
|
||||
limited: {
|
||||
docIdDigest: docId,
|
||||
sourceDocIdDigest: undefined,
|
||||
isImport: false,
|
||||
fileType: undefined,
|
||||
isSaved: false,
|
||||
},
|
||||
});
|
||||
return docId;
|
||||
}
|
||||
|
||||
private _logDocumentCreatedTelemetryEvent(req: Request, metadata: TelemetryMetadataByLevel) {
|
||||
const mreq = req as RequestWithLogin;
|
||||
this._grist.getTelemetry().logEvent('documentCreated', _.merge({
|
||||
full: {
|
||||
userId: mreq.userId,
|
||||
altSessionId: mreq.altSessionId,
|
||||
},
|
||||
}, metadata))
|
||||
.catch(e => log.error('failed to log telemetry event documentCreated', e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for read access to the given document, and return its
|
||||
* canonical docId. Throws error if read access not available.
|
||||
|
||||
@@ -12,6 +12,7 @@ import {DocCreationInfo, DocEntry, DocListAPI, OpenDocMode, OpenLocalDocResult}
|
||||
import {FilteredDocUsageSummary} from 'app/common/DocUsage';
|
||||
import {Invite} from 'app/common/sharing';
|
||||
import {tbind} from 'app/common/tbind';
|
||||
import {TelemetryMetadataByLevel} from 'app/common/Telemetry';
|
||||
import {NEW_DOCUMENT_CODE} from 'app/common/UserAPI';
|
||||
import {HomeDBManager} from 'app/gen-server/lib/HomeDBManager';
|
||||
import {assertAccess, Authorizer, DocAuthorizer, DummyAuthorizer, isSingleUserMode} from 'app/server/lib/Authorizer';
|
||||
@@ -31,6 +32,7 @@ import log from 'app/server/lib/log';
|
||||
import {ActiveDoc} from './ActiveDoc';
|
||||
import {PluginManager} from './PluginManager';
|
||||
import {getFileUploadInfo, globalUploadSet, makeAccessId, UploadInfo} from './uploads';
|
||||
import merge = require('lodash/merge');
|
||||
import noop = require('lodash/noop');
|
||||
|
||||
// A TTL in milliseconds to use for material that can easily be recomputed / refetched
|
||||
@@ -202,10 +204,11 @@ export class DocManager extends EventEmitter {
|
||||
documentName?: string,
|
||||
workspaceId?: number,
|
||||
browserSettings?: BrowserSettings,
|
||||
telemetryMetadata?: TelemetryMetadataByLevel,
|
||||
}): Promise<DocCreationInfo> {
|
||||
if (!this._homeDbManager) { throw new Error("HomeDbManager not available"); }
|
||||
|
||||
const {userId, uploadId, documentName, workspaceId, browserSettings} = options;
|
||||
const {userId, uploadId, documentName, workspaceId, browserSettings, telemetryMetadata} = options;
|
||||
const accessId = this.makeAccessId(userId);
|
||||
const docSession = makeExceptionalDocSession('nascent', {browserSettings});
|
||||
const register = async (docId: string, uploadBaseFilename: string) => {
|
||||
@@ -222,13 +225,23 @@ export class DocManager extends EventEmitter {
|
||||
throw new ApiError(queryResult.errMessage || 'unable to add imported document', queryResult.status);
|
||||
}
|
||||
};
|
||||
return this._doImportDoc(docSession,
|
||||
globalUploadSet.getUploadInfo(uploadId, accessId), {
|
||||
naming: workspaceId ? 'saved' : 'unsaved',
|
||||
register,
|
||||
userId,
|
||||
});
|
||||
const uploadInfo = globalUploadSet.getUploadInfo(uploadId, accessId);
|
||||
const docCreationInfo = await this._doImportDoc(docSession, uploadInfo, {
|
||||
naming: workspaceId ? 'saved' : 'unsaved',
|
||||
register,
|
||||
userId,
|
||||
});
|
||||
|
||||
this.gristServer.getTelemetry().logEvent('documentCreated', merge({
|
||||
limited: {
|
||||
docIdDigest: docCreationInfo.id,
|
||||
fileType: uploadInfo.files[0].ext.trim().slice(1),
|
||||
isSaved: workspaceId !== undefined,
|
||||
},
|
||||
}, telemetryMetadata))
|
||||
.catch(e => log.error('failed to log telemetry event documentCreated', e));
|
||||
|
||||
return docCreationInfo;
|
||||
// The imported document is associated with the worker that did the import.
|
||||
// We could break that association (see /api/docs/:docId/assign for how) if
|
||||
// we start using dedicated import workers.
|
||||
|
||||
@@ -670,7 +670,7 @@ export class FlexServer implements GristServer {
|
||||
|
||||
// ApiServer's constructor adds endpoints to the app.
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
new ApiServer(this.app, this._dbManager, this._widgetRepository = buildWidgetRepository());
|
||||
new ApiServer(this, this.app, this._dbManager, this._widgetRepository = buildWidgetRepository());
|
||||
}
|
||||
|
||||
public addBillingApi() {
|
||||
|
||||
Reference in New Issue
Block a user