mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +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:
		
							parent
							
								
									76e822eb23
								
							
						
					
					
						commit
						40c5f7b738
					
				@ -353,6 +353,45 @@ export const TelemetryContracts: TelemetryContracts = {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  documentCreated: {
 | 
				
			||||||
 | 
					    description: 'Triggered when a document is created.',
 | 
				
			||||||
 | 
					    minimumTelemetryLevel: Level.limited,
 | 
				
			||||||
 | 
					    retentionPeriod: 'indefinitely',
 | 
				
			||||||
 | 
					    metadataContracts: {
 | 
				
			||||||
 | 
					      docIdDigest: {
 | 
				
			||||||
 | 
					        description: 'A hash of the id of the created document.',
 | 
				
			||||||
 | 
					        dataType: 'string',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      sourceDocIdDigest: {
 | 
				
			||||||
 | 
					        description: 'A hash of the id of the source document, if the document was '
 | 
				
			||||||
 | 
					          + 'duplicated from an existing document.',
 | 
				
			||||||
 | 
					        dataType: 'string',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      isImport: {
 | 
				
			||||||
 | 
					        description: 'Whether the document was created by import.',
 | 
				
			||||||
 | 
					        dataType: 'boolean',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      isSaved: {
 | 
				
			||||||
 | 
					        description: 'Whether the document was saved to a workspace.',
 | 
				
			||||||
 | 
					        dataType: 'boolean',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      fileType: {
 | 
				
			||||||
 | 
					        description: 'If the document was created by import, the file extension '
 | 
				
			||||||
 | 
					          + 'of the file that was imported.',
 | 
				
			||||||
 | 
					        dataType: 'string',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      userId: {
 | 
				
			||||||
 | 
					        description: 'The id of the user that triggered this event.',
 | 
				
			||||||
 | 
					        dataType: 'number',
 | 
				
			||||||
 | 
					        minimumTelemetryLevel: Level.full,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      altSessionId: {
 | 
				
			||||||
 | 
					        description: 'A random, session-based identifier for the user that triggered this event.',
 | 
				
			||||||
 | 
					        dataType: 'string',
 | 
				
			||||||
 | 
					        minimumTelemetryLevel: Level.full,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  documentForked: {
 | 
					  documentForked: {
 | 
				
			||||||
    description: 'Triggered when a document is forked.',
 | 
					    description: 'Triggered when a document is forked.',
 | 
				
			||||||
    minimumTelemetryLevel: Level.limited,
 | 
					    minimumTelemetryLevel: Level.limited,
 | 
				
			||||||
@ -898,6 +937,7 @@ export const TelemetryEvents = StringUnion(
 | 
				
			|||||||
  'beaconArticleViewed',
 | 
					  'beaconArticleViewed',
 | 
				
			||||||
  'beaconEmailSent',
 | 
					  'beaconEmailSent',
 | 
				
			||||||
  'beaconSearch',
 | 
					  'beaconSearch',
 | 
				
			||||||
 | 
					  'documentCreated',
 | 
				
			||||||
  'documentForked',
 | 
					  'documentForked',
 | 
				
			||||||
  'documentOpened',
 | 
					  'documentOpened',
 | 
				
			||||||
  'documentUsage',
 | 
					  'documentUsage',
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ import {getAuthorizedUserId, getUserId, getUserProfiles, RequestWithLogin} from
 | 
				
			|||||||
import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession';
 | 
					import {getSessionUser, linkOrgWithEmail} from 'app/server/lib/BrowserSession';
 | 
				
			||||||
import {expressWrap} from 'app/server/lib/expressWrap';
 | 
					import {expressWrap} from 'app/server/lib/expressWrap';
 | 
				
			||||||
import {RequestWithOrg} from 'app/server/lib/extractOrg';
 | 
					import {RequestWithOrg} from 'app/server/lib/extractOrg';
 | 
				
			||||||
 | 
					import {GristServer} from 'app/server/lib/GristServer';
 | 
				
			||||||
import {getTemplateOrg} from 'app/server/lib/gristSettings';
 | 
					import {getTemplateOrg} from 'app/server/lib/gristSettings';
 | 
				
			||||||
import log from 'app/server/lib/log';
 | 
					import log from 'app/server/lib/log';
 | 
				
			||||||
import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam,
 | 
					import {addPermit, clearSessionCacheIfNeeded, getDocScope, getScope, integerParam,
 | 
				
			||||||
@ -100,6 +101,7 @@ export class ApiServer {
 | 
				
			|||||||
   * to apply to these routes, and trustOrigin too for cross-domain requests.
 | 
					   * to apply to these routes, and trustOrigin too for cross-domain requests.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
 | 
					    private _gristServer: GristServer,
 | 
				
			||||||
    private _app: express.Application,
 | 
					    private _app: express.Application,
 | 
				
			||||||
    private _dbManager: HomeDBManager,
 | 
					    private _dbManager: HomeDBManager,
 | 
				
			||||||
    private _widgetRepository: IWidgetRepository
 | 
					    private _widgetRepository: IWidgetRepository
 | 
				
			||||||
@ -235,8 +237,23 @@ export class ApiServer {
 | 
				
			|||||||
    // POST /api/workspaces/:wid/docs
 | 
					    // POST /api/workspaces/:wid/docs
 | 
				
			||||||
    // Create a new doc owned by the specific workspace.
 | 
					    // Create a new doc owned by the specific workspace.
 | 
				
			||||||
    this._app.post('/api/workspaces/:wid/docs', expressWrap(async (req, res) => {
 | 
					    this._app.post('/api/workspaces/:wid/docs', expressWrap(async (req, res) => {
 | 
				
			||||||
 | 
					      const mreq = req as RequestWithLogin;
 | 
				
			||||||
      const wsId = integerParam(req.params.wid, 'wid');
 | 
					      const wsId = integerParam(req.params.wid, 'wid');
 | 
				
			||||||
      const query = await this._dbManager.addDocument(getScope(req), wsId, req.body);
 | 
					      const query = await this._dbManager.addDocument(getScope(req), wsId, req.body);
 | 
				
			||||||
 | 
					      this._gristServer.getTelemetry().logEvent('documentCreated', {
 | 
				
			||||||
 | 
					        limited: {
 | 
				
			||||||
 | 
					          docIdDigest: query.data!,
 | 
				
			||||||
 | 
					          sourceDocIdDigest: undefined,
 | 
				
			||||||
 | 
					          isImport: false,
 | 
				
			||||||
 | 
					          fileType: undefined,
 | 
				
			||||||
 | 
					          isSaved: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        full: {
 | 
				
			||||||
 | 
					          userId: mreq.userId,
 | 
				
			||||||
 | 
					          altSessionId: mreq.altSessionId,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(e => log.error('failed to log telemetry event documentCreated', e));
 | 
				
			||||||
      return sendReply(req, res, query);
 | 
					      return sendReply(req, res, query);
 | 
				
			||||||
    }));
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,7 @@ import {SchemaTypes} from "app/common/schema";
 | 
				
			|||||||
import {SortFunc} from 'app/common/SortFunc';
 | 
					import {SortFunc} from 'app/common/SortFunc';
 | 
				
			||||||
import {Sort} from 'app/common/SortSpec';
 | 
					import {Sort} from 'app/common/SortSpec';
 | 
				
			||||||
import {MetaRowRecord} from 'app/common/TableData';
 | 
					import {MetaRowRecord} from 'app/common/TableData';
 | 
				
			||||||
 | 
					import {TelemetryMetadataByLevel} from "app/common/Telemetry";
 | 
				
			||||||
import {WebhookFields} from "app/common/Triggers";
 | 
					import {WebhookFields} from "app/common/Triggers";
 | 
				
			||||||
import TriggersTI from 'app/common/Triggers-ti';
 | 
					import TriggersTI from 'app/common/Triggers-ti';
 | 
				
			||||||
import {DocReplacementOptions, DocState, DocStateComparison, DocStates, NEW_DOCUMENT_CODE} from 'app/common/UserAPI';
 | 
					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
 | 
					    // 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.)
 | 
					    // actual file uploads, so no worries here about large request bodies.)
 | 
				
			||||||
    this._app.post('/api/workspaces/:wid/import', expressWrap(async (req, res) => {
 | 
					    this._app.post('/api/workspaces/:wid/import', expressWrap(async (req, res) => {
 | 
				
			||||||
 | 
					      const mreq = req as RequestWithLogin;
 | 
				
			||||||
      const userId = getUserId(req);
 | 
					      const userId = getUserId(req);
 | 
				
			||||||
      const wsId = integerParam(req.params.wid, 'wid');
 | 
					      const wsId = integerParam(req.params.wid, 'wid');
 | 
				
			||||||
      const uploadId = integerParam(req.body.uploadId, 'uploadId');
 | 
					      const uploadId = integerParam(req.body.uploadId, 'uploadId');
 | 
				
			||||||
@ -1158,6 +1160,16 @@ export class DocWorkerApi {
 | 
				
			|||||||
        uploadId,
 | 
					        uploadId,
 | 
				
			||||||
        workspaceId: wsId,
 | 
					        workspaceId: wsId,
 | 
				
			||||||
        browserSettings: req.body.browserSettings,
 | 
					        browserSettings: req.body.browserSettings,
 | 
				
			||||||
 | 
					        telemetryMetadata: {
 | 
				
			||||||
 | 
					          limited: {
 | 
				
			||||||
 | 
					            isImport: true,
 | 
				
			||||||
 | 
					            sourceDocIdDigest: undefined,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          full: {
 | 
				
			||||||
 | 
					            userId: mreq.userId,
 | 
				
			||||||
 | 
					            altSessionId: mreq.altSessionId,
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      res.json(result);
 | 
					      res.json(result);
 | 
				
			||||||
    }));
 | 
					    }));
 | 
				
			||||||
@ -1243,6 +1255,7 @@ export class DocWorkerApi {
 | 
				
			|||||||
     * TODO: unify this with the other document creation and import endpoints.
 | 
					     * TODO: unify this with the other document creation and import endpoints.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    this._app.post('/api/docs', checkAnonymousCreation, expressWrap(async (req, res) => {
 | 
					    this._app.post('/api/docs', checkAnonymousCreation, expressWrap(async (req, res) => {
 | 
				
			||||||
 | 
					      const mreq = req as RequestWithLogin;
 | 
				
			||||||
      const userId = getUserId(req);
 | 
					      const userId = getUserId(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let uploadId: number|undefined;
 | 
					      let uploadId: number|undefined;
 | 
				
			||||||
@ -1279,6 +1292,16 @@ export class DocWorkerApi {
 | 
				
			|||||||
          documentName: optStringParam(parameters.documentName, 'documentName'),
 | 
					          documentName: optStringParam(parameters.documentName, 'documentName'),
 | 
				
			||||||
          workspaceId,
 | 
					          workspaceId,
 | 
				
			||||||
          browserSettings,
 | 
					          browserSettings,
 | 
				
			||||||
 | 
					          telemetryMetadata: {
 | 
				
			||||||
 | 
					            limited: {
 | 
				
			||||||
 | 
					              isImport: true,
 | 
				
			||||||
 | 
					              sourceDocIdDigest: undefined,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            full: {
 | 
				
			||||||
 | 
					              userId: mreq.userId,
 | 
				
			||||||
 | 
					              altSessionId: mreq.altSessionId,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        docId = result.id;
 | 
					        docId = result.id;
 | 
				
			||||||
      } else if (workspaceId !== undefined) {
 | 
					      } else if (workspaceId !== undefined) {
 | 
				
			||||||
@ -1304,6 +1327,7 @@ export class DocWorkerApi {
 | 
				
			|||||||
    documentName: string,
 | 
					    documentName: string,
 | 
				
			||||||
    asTemplate?: boolean,
 | 
					    asTemplate?: boolean,
 | 
				
			||||||
  }): Promise<string> {
 | 
					  }): Promise<string> {
 | 
				
			||||||
 | 
					    const mreq = req as RequestWithLogin;
 | 
				
			||||||
    const {userId, sourceDocumentId, workspaceId, documentName, asTemplate = false} = options;
 | 
					    const {userId, sourceDocumentId, workspaceId, documentName, asTemplate = false} = options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // First, upload a copy of the document.
 | 
					    // First, upload a copy of the document.
 | 
				
			||||||
@ -1326,6 +1350,16 @@ export class DocWorkerApi {
 | 
				
			|||||||
      uploadId: uploadResult.uploadId,
 | 
					      uploadId: uploadResult.uploadId,
 | 
				
			||||||
      documentName,
 | 
					      documentName,
 | 
				
			||||||
      workspaceId,
 | 
					      workspaceId,
 | 
				
			||||||
 | 
					      telemetryMetadata: {
 | 
				
			||||||
 | 
					        limited: {
 | 
				
			||||||
 | 
					          isImport: false,
 | 
				
			||||||
 | 
					          sourceDocIdDigest: sourceDocumentId,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        full: {
 | 
				
			||||||
 | 
					          userId: mreq.userId,
 | 
				
			||||||
 | 
					          altSessionId: mreq.altSessionId,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return result.id;
 | 
					    return result.id;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -1341,7 +1375,15 @@ export class DocWorkerApi {
 | 
				
			|||||||
    if (status !== 200) {
 | 
					    if (status !== 200) {
 | 
				
			||||||
      throw new ApiError(errMessage || 'unable to create document', status);
 | 
					      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!;
 | 
					    return data!;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1365,9 +1407,29 @@ export class DocWorkerApi {
 | 
				
			|||||||
      }),
 | 
					      }),
 | 
				
			||||||
      docId
 | 
					      docId
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    this._logDocumentCreatedTelemetryEvent(req, {
 | 
				
			||||||
 | 
					      limited: {
 | 
				
			||||||
 | 
					        docIdDigest: docId,
 | 
				
			||||||
 | 
					        sourceDocIdDigest: undefined,
 | 
				
			||||||
 | 
					        isImport: false,
 | 
				
			||||||
 | 
					        fileType: undefined,
 | 
				
			||||||
 | 
					        isSaved: false,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    return docId;
 | 
					    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
 | 
					   * Check for read access to the given document, and return its
 | 
				
			||||||
   * canonical docId.  Throws error if read access not available.
 | 
					   * 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 {FilteredDocUsageSummary} from 'app/common/DocUsage';
 | 
				
			||||||
import {Invite} from 'app/common/sharing';
 | 
					import {Invite} from 'app/common/sharing';
 | 
				
			||||||
import {tbind} from 'app/common/tbind';
 | 
					import {tbind} from 'app/common/tbind';
 | 
				
			||||||
 | 
					import {TelemetryMetadataByLevel} from 'app/common/Telemetry';
 | 
				
			||||||
import {NEW_DOCUMENT_CODE} from 'app/common/UserAPI';
 | 
					import {NEW_DOCUMENT_CODE} from 'app/common/UserAPI';
 | 
				
			||||||
import {HomeDBManager} from 'app/gen-server/lib/HomeDBManager';
 | 
					import {HomeDBManager} from 'app/gen-server/lib/HomeDBManager';
 | 
				
			||||||
import {assertAccess, Authorizer, DocAuthorizer, DummyAuthorizer, isSingleUserMode} from 'app/server/lib/Authorizer';
 | 
					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 {ActiveDoc} from './ActiveDoc';
 | 
				
			||||||
import {PluginManager} from './PluginManager';
 | 
					import {PluginManager} from './PluginManager';
 | 
				
			||||||
import {getFileUploadInfo, globalUploadSet, makeAccessId, UploadInfo} from './uploads';
 | 
					import {getFileUploadInfo, globalUploadSet, makeAccessId, UploadInfo} from './uploads';
 | 
				
			||||||
 | 
					import merge = require('lodash/merge');
 | 
				
			||||||
import noop = require('lodash/noop');
 | 
					import noop = require('lodash/noop');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A TTL in milliseconds to use for material that can easily be recomputed / refetched
 | 
					// 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,
 | 
					    documentName?: string,
 | 
				
			||||||
    workspaceId?: number,
 | 
					    workspaceId?: number,
 | 
				
			||||||
    browserSettings?: BrowserSettings,
 | 
					    browserSettings?: BrowserSettings,
 | 
				
			||||||
 | 
					    telemetryMetadata?: TelemetryMetadataByLevel,
 | 
				
			||||||
  }): Promise<DocCreationInfo> {
 | 
					  }): Promise<DocCreationInfo> {
 | 
				
			||||||
    if (!this._homeDbManager) { throw new Error("HomeDbManager not available"); }
 | 
					    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 accessId = this.makeAccessId(userId);
 | 
				
			||||||
    const docSession = makeExceptionalDocSession('nascent', {browserSettings});
 | 
					    const docSession = makeExceptionalDocSession('nascent', {browserSettings});
 | 
				
			||||||
    const register = async (docId: string, uploadBaseFilename: string) => {
 | 
					    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);
 | 
					        throw new ApiError(queryResult.errMessage || 'unable to add imported document', queryResult.status);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return this._doImportDoc(docSession,
 | 
					    const uploadInfo = globalUploadSet.getUploadInfo(uploadId, accessId);
 | 
				
			||||||
                             globalUploadSet.getUploadInfo(uploadId, accessId), {
 | 
					    const docCreationInfo = await this._doImportDoc(docSession, uploadInfo, {
 | 
				
			||||||
                               naming: workspaceId ? 'saved' : 'unsaved',
 | 
					      naming: workspaceId ? 'saved' : 'unsaved',
 | 
				
			||||||
                               register,
 | 
					      register,
 | 
				
			||||||
                               userId,
 | 
					      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.
 | 
					    // 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 could break that association (see /api/docs/:docId/assign for how) if
 | 
				
			||||||
    // we start using dedicated import workers.
 | 
					    // we start using dedicated import workers.
 | 
				
			||||||
 | 
				
			|||||||
@ -670,7 +670,7 @@ export class FlexServer implements GristServer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // ApiServer's constructor adds endpoints to the app.
 | 
					    // ApiServer's constructor adds endpoints to the app.
 | 
				
			||||||
    // tslint:disable-next-line:no-unused-expression
 | 
					    // 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() {
 | 
					  public addBillingApi() {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user