From be2211a8ccc08be2dac9364570ff218fbdeb17cf Mon Sep 17 00:00:00 2001 From: Shota Gvinepadze Date: Thu, 23 Jul 2020 19:57:42 +0400 Subject: [PATCH] Add analytics to the command autocomplete (#4597) * Add analytics to the command autocomplete * Refactor analytics * Refactor reset method --- app/actions/views/root.js | 4 +- app/actions/views/user.js | 5 +- .../slash_suggestion/slash_suggestion.js | 6 +- .../uploads/upload_item/upload_item.js | 3 +- app/init/analytics.ts | 191 +++++++++---- app/init/credentials.js | 6 +- app/init/global_event_handler.js | 12 +- app/mm-redux/actions/channels.ts | 17 +- app/mm-redux/actions/gifs.ts | 6 +- app/mm-redux/actions/integrations.ts | 27 +- app/mm-redux/actions/posts.ts | 5 +- app/mm-redux/actions/search.ts | 4 +- app/mm-redux/actions/users.ts | 10 +- app/mm-redux/client/client4.ts | 256 ++++++++---------- 14 files changed, 305 insertions(+), 247 deletions(-) diff --git a/app/actions/views/root.js b/app/actions/views/root.js index 4f586d0bd..ce7d44c1e 100644 --- a/app/actions/views/root.js +++ b/app/actions/views/root.js @@ -4,7 +4,7 @@ import {batchActions} from 'redux-batched-actions'; import {NavigationTypes, ViewTypes} from '@constants'; -import {recordTime} from '@init/analytics.ts'; +import {analytics} from '@init/analytics.ts'; import {ChannelTypes, GeneralTypes, TeamTypes} from '@mm-redux/action_types'; import {fetchMyChannelsAndMembers} from '@mm-redux/actions/channels'; import {getDataRetentionPolicy} from '@mm-redux/actions/general'; @@ -180,7 +180,7 @@ export function recordLoadTime(screenName, category) { return async (dispatch, getState) => { const {currentUserId} = getState().entities.users; - recordTime(screenName, category, currentUserId); + analytics.recordTime(screenName, category, currentUserId); }; } diff --git a/app/actions/views/user.js b/app/actions/views/user.js index 734a27307..55de593af 100644 --- a/app/actions/views/user.js +++ b/app/actions/views/user.js @@ -18,6 +18,7 @@ import {getCurrentUserId, getStatusForUserId} from '@mm-redux/selectors/entities import {setAppCredentials} from 'app/init/credentials'; import {setCSRFFromCookie} from '@utils/security'; import {getDeviceTimezone} from '@utils/timezone'; +import {analytics} from '@init/analytics.ts'; const HTTP_UNAUTHORIZED = 401; @@ -96,8 +97,8 @@ export function loadMe(user, deviceToken, skipDispatch = false) { } try { - Client4.setUserId(data.user.id); - Client4.setUserRoles(data.user.roles); + analytics.setUserId(data.user.id); + analytics.setUserRoles(data.user.roles); // Execute all other requests in parallel const teamsRequest = Client4.getMyTeams(); diff --git a/app/components/autocomplete/slash_suggestion/slash_suggestion.js b/app/components/autocomplete/slash_suggestion/slash_suggestion.js index 39a104105..48fcdf02f 100644 --- a/app/components/autocomplete/slash_suggestion/slash_suggestion.js +++ b/app/components/autocomplete/slash_suggestion/slash_suggestion.js @@ -14,6 +14,7 @@ import {makeStyleSheetFromTheme} from 'app/utils/theme'; import SlashSuggestionItem from './slash_suggestion_item'; import {Client4} from '@mm-redux/client'; import {isMinimumServerVersion} from '@mm-redux/utils/helpers'; +import {analytics} from '@init/analytics.ts'; const TIME_BEFORE_NEXT_COMMAND_REQUEST = 1000 * 60 * 5; @@ -90,12 +91,12 @@ export default class SlashSuggestion extends PureComponent { const matches = this.filterSlashSuggestions(nextValue.substring(1), nextCommands); this.updateSuggestions(matches); } else if (isMinimumServerVersion(Client4.getServerVersion(), 5, 24)) { - if (nextProps.suggestions === this.props.suggestions) { + if (nextSuggestions === this.props.suggestions) { const args = { channel_id: this.props.channelId, ...(this.props.rootId && {root_id: this.props.rootId, parent_id: this.props.rootId}), }; - this.props.actions.getCommandAutocompleteSuggestions(nextProps.value, nextProps.currentTeamId, args); + this.props.actions.getCommandAutocompleteSuggestions(nextValue, nextTeamId, args); } else { const matches = []; nextSuggestions.forEach((sug) => { @@ -151,6 +152,7 @@ export default class SlashSuggestion extends PureComponent { completeSuggestion = (command) => { const {onChangeText} = this.props; + analytics.trackCommand('complete_suggestion', `/${command} `); // We are going to set a double / on iOS to prevent the auto correct from taking over and replacing it // with the wrong value, this is a hack but I could not found another way to solve it diff --git a/app/components/post_draft/uploads/upload_item/upload_item.js b/app/components/post_draft/uploads/upload_item/upload_item.js index 332ecb81c..d198ceb98 100644 --- a/app/components/post_draft/uploads/upload_item/upload_item.js +++ b/app/components/post_draft/uploads/upload_item/upload_item.js @@ -18,6 +18,7 @@ import ImageCacheManager from '@utils/image_cache_manager'; import UploadRemove from './upload_remove'; import UploadRetry from './upload_retry'; +import {analytics} from '@init/analytics.ts'; export default class UploadItem extends PureComponent { static propTypes = { @@ -147,7 +148,7 @@ export default class UploadItem extends PureComponent { fileInfo, ]; - Client4.trackEvent('api', 'api_files_upload'); + analytics.trackAPI('api_files_upload'); const certificate = await mattermostBucket.getPreference('cert'); const options = { diff --git a/app/init/analytics.ts b/app/init/analytics.ts index 45111b880..cf53e90a5 100644 --- a/app/init/analytics.ts +++ b/app/init/analytics.ts @@ -7,6 +7,7 @@ import {Dimensions} from 'react-native'; import LocalConfig from '@assets/config.json'; import {Config} from '@mm-redux/types/config'; import tracker from '@utils/time_tracker'; +import {isSystemAdmin} from '@mm-redux/utils/user_utils'; type RudderClient = { setup(key: string, options: any): Promise; @@ -16,69 +17,147 @@ type RudderClient = { reset(): Promise; } -let diagnosticId: string | undefined; -export let analytics: RudderClient | null = null; -export let context: any; +class Analytics { + analytics: RudderClient | null = null; + context: any; + diagnosticId: string | undefined; -export async function init(config: Config) { - if (!analytics) { - analytics = require('@rudderstack/rudder-sdk-react-native').default; + userRoles: string | null = null; + userId = ''; + + async init(config: Config) { + this.analytics = require('@rudderstack/rudder-sdk-react-native').default; + + if (this.analytics) { + const {height, width} = Dimensions.get('window'); + this.diagnosticId = config.DiagnosticId; + + if (this.diagnosticId) { + await this.analytics.setup(LocalConfig.RudderApiKey, { + dataPlaneUrl: 'https://pdat.matterlytics.com', + recordScreenViews: true, + flushQueueSize: 20, + }); + + this.context = { + app: { + version: DeviceInfo.getVersion(), + build: DeviceInfo.getBuildNumber(), + }, + device: { + dimensions: { + height, + width, + }, + isTablet: DeviceInfo.isTablet(), + os: DeviceInfo.getSystemVersion(), + }, + ip: '0.0.0.0', + server: config.Version, + }; + + this.analytics.identify( + this.diagnosticId, + this.context, + ); + } else { + this.analytics.reset(); + } + } + + return this.analytics; } - if (analytics) { - const {height, width} = Dimensions.get('window'); - diagnosticId = config.DiagnosticId; - - if (diagnosticId) { - await analytics.setup(LocalConfig.RudderApiKey, { - dataPlaneUrl: 'https://pdat.matterlytics.com', - recordScreenViews: true, - flushQueueSize: 20, - }); - - context = { - app: { - version: DeviceInfo.getVersion(), - build: DeviceInfo.getBuildNumber(), - }, - device: { - dimensions: { - height, - width, - }, - isTablet: DeviceInfo.isTablet(), - os: DeviceInfo.getSystemVersion(), - }, - ip: '0.0.0.0', - server: config.Version, - }; - - analytics.identify( - diagnosticId, - context, - ); - } else { - analytics.reset(); + async reset() { + this.userId = ''; + this.userRoles = null; + if (this.analytics) { + await this.analytics.reset(); } } - return analytics; -} + setUserId(userId: string) { + this.userId = userId; + } -export function recordTime(screenName: string, category: string, userId: string) { - if (analytics) { - const track: Record = tracker; - const startTime: number = track[category]; - track[category] = 0; - analytics.screen( - screenName, { - userId: diagnosticId, - context, - properties: { - user_actual_id: userId, - time: Date.now() - startTime, + setUserRoles(roles: string) { + this.userRoles = roles; + } + + trackEvent(category: string, event: string, props?: any) { + if (!this.analytics) { + return; + } + + const properties = Object.assign({ + category, + type: event, + user_actual_role: this.userRoles && isSystemAdmin(this.userRoles) ? 'system_admin, system_user' : 'system_user', + user_actual_id: this.userId, + }, props); + const options = { + context: this.context, + anonymousId: '00000000000000000000000000', + }; + + this.analytics.track(event, properties, options); + } + + recordTime(screenName: string, category: string, userId: string) { + if (this.analytics) { + const track: Record = tracker; + const startTime: number = track[category]; + track[category] = 0; + this.analytics.screen( + screenName, { + userId: this.diagnosticId, + context: this.context, + properties: { + user_actual_id: userId, + time: Date.now() - startTime, + }, }, - }, - ); + ); + } + } + + trackAPI(event: string, props?: any) { + this.trackEvent('api', event, props); + } + + trackCommand(event: string, command: string, errorMessage?: string) { + const sanitizedCommand = this.sanitizeCommand(command); + let props: any; + if (errorMessage) { + props = {command: sanitizedCommand, error: errorMessage}; + } else { + props = {command: sanitizedCommand}; + } + + this.trackEvent('command', event, props); + } + + trackAction(event: string, props?: any) { + this.trackEvent('action', event, props); + } + + sanitizeCommand(userInput: string): string { + const commandList = ['agenda', 'autolink', 'away', 'bot-server', 'code', 'collapse', + 'dnd', 'echo', 'expand', 'export', 'giphy', 'github', 'groupmsg', 'header', 'help', + 'invite', 'invite_people', 'jira', 'jitsi', 'join', 'kick', 'leave', 'logout', 'me', + 'msg', 'mute', 'nc', 'offline', 'online', 'open', 'poll', 'poll2', 'post-mortem', + 'purpose', 'recommend', 'remove', 'rename', 'search', 'settings', 'shortcuts', + 'shrug', 'standup', 'todo', 'wrangler', 'zoom']; + const index = userInput.indexOf(' '); + if (index === -1) { + return userInput[0]; + } + const command = userInput.substring(1, index); + if (commandList.includes(command)) { + return command; + } + return 'custom_command'; } } + +export const analytics = new Analytics(); diff --git a/app/init/credentials.js b/app/init/credentials.js index 309fbf3fc..e48d1eaab 100644 --- a/app/init/credentials.js +++ b/app/init/credentials.js @@ -9,6 +9,7 @@ import {Client4} from '@mm-redux/client'; import mattermostManaged from 'app/mattermost_managed'; import EphemeralStore from 'app/store/ephemeral_store'; import {setCSRFFromCookie} from 'app/utils/security'; +import {analytics} from '@init/analytics.ts'; const CURRENT_SERVER = '@currentServerUrl'; @@ -56,7 +57,6 @@ export const removeAppCredentials = async () => { Client4.setCSRF(''); Client4.serverVersion = ''; - Client4.setUserId(''); Client4.setToken(''); Client4.setUrl(''); @@ -84,7 +84,7 @@ async function getCredentialsFromGenericKeyChain() { // if for any case the url and the token aren't valid proceed with re-hydration if (url && url !== 'undefined' && token && token !== 'undefined') { - Client4.setUserId(currentUserId); + analytics.setUserId(currentUserId); Client4.setUrl(url); Client4.setToken(token); await setCSRFFromCookie(url); @@ -116,7 +116,7 @@ async function getInternetCredentials(url) { if (token && token !== 'undefined') { EphemeralStore.deviceToken = deviceToken; - Client4.setUserId(currentUserId); + analytics.setUserId(currentUserId); Client4.setUrl(url); Client4.setToken(token); await setCSRFFromCookie(url); diff --git a/app/init/global_event_handler.js b/app/init/global_event_handler.js index 7f1e2ac30..9a16c4b17 100644 --- a/app/init/global_event_handler.js +++ b/app/init/global_event_handler.js @@ -42,12 +42,11 @@ import PushNotifications from 'app/push_notifications'; import {getAppCredentials, removeAppCredentials} from './credentials'; import emmProvider from './emm_provider'; +import {analytics} from '@init/analytics.ts'; const {StatusBarManager} = NativeModules; const PROMPT_IN_APP_PIN_CODE_AFTER = 5 * 1000; -let analytics; - class GlobalEventHandler { constructor() { this.pushNotificationListener = false; @@ -120,13 +119,10 @@ class GlobalEventHandler { configureAnalytics = async () => { const state = Store.redux.getState(); const config = getConfig(state); - const initAnalytics = require('./analytics').init; if (config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && LocalConfig.RudderApiKey) { - analytics = await initAnalytics(config); + await analytics.init(config); } - - return analytics; }; onAppStateChange = (appState) => { @@ -204,9 +200,7 @@ class GlobalEventHandler { Store.redux.dispatch(closeWebSocket(false)); Store.redux.dispatch(setServerVersion('')); - if (analytics) { - await analytics.reset(); - } + await analytics.reset(); mattermostBucket.removePreference('cert'); mattermostBucket.removePreference('emm'); diff --git a/app/mm-redux/actions/channels.ts b/app/mm-redux/actions/channels.ts index e47b078d9..b1196cef5 100644 --- a/app/mm-redux/actions/channels.ts +++ b/app/mm-redux/actions/channels.ts @@ -25,6 +25,7 @@ import {logError} from './errors'; import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; import {getMissingProfilesByIds} from './users'; import {loadRolesIfNeeded} from './roles'; +import {analytics} from '@init/analytics.ts'; export function selectChannel(channelId: string) { return { @@ -626,7 +627,7 @@ export function leaveChannel(channelId: string): ActionFunc { const channel = channels[channelId]; const member = myMembers[channelId]; - Client4.trackEvent('action', 'action_channels_leave', {channel_id: channelId}); + analytics.trackAction('action_channels_leave', {channel_id: channelId}); dispatch({ type: ChannelTypes.LEAVE_CHANNEL, @@ -679,7 +680,7 @@ export function joinChannel(userId: string, teamId: string, channelId: string, c return {error}; } - Client4.trackEvent('action', 'action_channels_join', {channel_id: channelId}); + analytics.trackAction('action_channels_join', {channel_id: channelId}); dispatch(batchActions([ { @@ -1127,7 +1128,7 @@ export function addChannelMember(channelId: string, userId: string, postRootId = return {error}; } - Client4.trackEvent('action', 'action_channels_add_member', {channel_id: channelId}); + analytics.trackAction('action_channels_add_member', {channel_id: channelId}); dispatch(batchActions([ { @@ -1158,7 +1159,7 @@ export function removeChannelMember(channelId: string, userId: string): ActionFu return {error}; } - Client4.trackEvent('action', 'action_channels_remove_member', {channel_id: channelId}); + analytics.trackAction('action_channels_remove_member', {channel_id: channelId}); dispatch(batchActions([ { @@ -1199,7 +1200,7 @@ export function updateChannelMemberRoles(channelId: string, userId: string, role export function updateChannelHeader(channelId: string, header: string): ActionFunc { return async (dispatch: DispatchFunc) => { - Client4.trackEvent('action', 'action_channels_update_header', {channel_id: channelId}); + analytics.trackAction('action_channels_update_header', {channel_id: channelId}); dispatch({ type: ChannelTypes.UPDATE_CHANNEL_HEADER, @@ -1215,7 +1216,7 @@ export function updateChannelHeader(channelId: string, header: string): ActionFu export function updateChannelPurpose(channelId: string, purpose: string): ActionFunc { return async (dispatch: DispatchFunc) => { - Client4.trackEvent('action', 'action_channels_update_purpose', {channel_id: channelId}); + analytics.trackAction('action_channels_update_purpose', {channel_id: channelId}); dispatch({ type: ChannelTypes.UPDATE_CHANNEL_PURPOSE, @@ -1394,7 +1395,7 @@ export function favoriteChannel(channelId: string): ActionFunc { value: 'true', }; - Client4.trackEvent('action', 'action_channels_favorite'); + analytics.trackAction('action_channels_favorite'); return dispatch(savePreferences(currentUserId, [preference])); }; @@ -1410,7 +1411,7 @@ export function unfavoriteChannel(channelId: string): ActionFunc { value: '', }; - Client4.trackEvent('action', 'action_channels_unfavorite'); + analytics.trackAction('action_channels_unfavorite'); return deletePreferences(currentUserId, [preference])(dispatch, getState); }; diff --git a/app/mm-redux/actions/gifs.ts b/app/mm-redux/actions/gifs.ts index 647f8b794..c63aeb630 100644 --- a/app/mm-redux/actions/gifs.ts +++ b/app/mm-redux/actions/gifs.ts @@ -1,10 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {GifTypes} from '@mm-redux/action_types'; -import {Client4} from '@mm-redux/client'; import gfycatSdk from '@mm-redux/utils/gfycat_sdk'; import {DispatchFunc, GetStateFunc} from '@mm-redux/types/actions'; import {GlobalState} from '@mm-redux/types/store'; +import {analytics} from '@init/analytics.ts'; // APP PROPS @@ -170,7 +170,7 @@ export function searchGfycat({searchText, count = 30, startIndex = 0}: { searchT const context = getState().entities.gifs.categories.tagsDict[searchText] ? 'category' : 'search'; - Client4.trackEvent( + analytics.trackEvent( 'gfycat', 'views', {context, count: json.gfycats.length, keyword: searchText}, @@ -204,7 +204,7 @@ export function searchCategory({tagName = '', gfyCount = 30, cursorPos = undefin dispatch(cacheGifsRequest(json.gfycats)); dispatch(receiveCategorySearch({tagName, json})); - Client4.trackEvent( + analytics.trackEvent( 'gfycat', 'views', {context: 'category', count: json.gfycats.length, keyword: tagName}, diff --git a/app/mm-redux/actions/integrations.ts b/app/mm-redux/actions/integrations.ts index 7c8373217..bb7ece7d1 100644 --- a/app/mm-redux/actions/integrations.ts +++ b/app/mm-redux/actions/integrations.ts @@ -6,13 +6,14 @@ import {Client4} from '@mm-redux/client'; import {getCurrentUserId} from '@mm-redux/selectors/entities/users'; import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; +import {analytics} from '@init/analytics.ts'; import {batchActions, DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions'; import {Command, DialogSubmission, IncomingWebhook, OAuthApp, OutgoingWebhook} from '@mm-redux/types/integrations'; import {logError} from './errors'; -import {bindClientFunc, forceLogoutIfNecessary} from './helpers'; +import {bindClientFunc, forceLogoutIfNecessary, requestSuccess, requestFailure} from './helpers'; export function createIncomingHook(hook: IncomingWebhook): ActionFunc { return bindClientFunc({ clientFunc: Client4.createIncomingWebhook, @@ -175,16 +176,20 @@ export function getAutocompleteCommands(teamId: string, page = 0, perPage: numbe } export function getCommandAutocompleteSuggestions(userInput: string, teamId: string, commandArgs: any): ActionFunc { - return bindClientFunc({ - clientFunc: Client4.getCommandAutocompleteSuggestionsList, - onSuccess: [IntegrationTypes.RECEIVED_COMMAND_SUGGESTIONS], - onFailure: IntegrationTypes.RECEIVED_COMMAND_SUGGESTIONS_FAILURE, - params: [ - userInput, - teamId, - commandArgs, - ], - }); + return async (dispatch: DispatchFunc) => { + let data: any = null; + try { + analytics.trackCommand('get_suggestions_initiated', userInput); + data = await Client4.getCommandAutocompleteSuggestionsList(userInput, teamId, commandArgs); + } catch (error) { + analytics.trackCommand('get_suggestions_failed', userInput, error.message); + dispatch(batchActions([logError(error), requestFailure(IntegrationTypes.RECEIVED_COMMAND_SUGGESTIONS_FAILURE, error)])); + return {error}; + } + analytics.trackCommand('get_suggestions_success', userInput); + dispatch(requestSuccess(IntegrationTypes.RECEIVED_COMMAND_SUGGESTIONS, data)); + return {data}; + }; } export function getCustomTeamCommands(teamId: string): ActionFunc { diff --git a/app/mm-redux/actions/posts.ts b/app/mm-redux/actions/posts.ts index e31fba0fb..42085e8fb 100644 --- a/app/mm-redux/actions/posts.ts +++ b/app/mm-redux/actions/posts.ts @@ -22,6 +22,7 @@ import {getMyChannelMember, markChannelAsUnread, markChannelAsRead, markChannelA import {getCustomEmojiByName, getCustomEmojisByName} from './emojis'; import {logError} from './errors'; import {forceLogoutIfNecessary} from './helpers'; +import {analytics} from '@init/analytics.ts'; import { deletePreferences, @@ -670,7 +671,7 @@ export function flagPost(postId: string) { value: 'true', }; - Client4.trackEvent('action', 'action_posts_flag'); + analytics.trackAction('action_posts_flag'); return savePreferences(currentUserId, [preference])(dispatch); }; @@ -1123,7 +1124,7 @@ export function unflagPost(postId: string) { name: postId, }; - Client4.trackEvent('action', 'action_posts_unflag'); + analytics.trackAction('action_posts_unflag'); return deletePreferences(currentUserId, [preference])(dispatch, getState); }; diff --git a/app/mm-redux/actions/search.ts b/app/mm-redux/actions/search.ts index 88479b9e1..d7fb2d76f 100644 --- a/app/mm-redux/actions/search.ts +++ b/app/mm-redux/actions/search.ts @@ -13,6 +13,8 @@ import {ActionResult, batchActions, DispatchFunc, GetStateFunc, ActionFunc} from import {RelationOneToOne} from '@mm-redux/types/utilities'; import {Post} from '@mm-redux/types/posts'; import {SearchParameter} from '@mm-redux/types/search'; +import {analytics} from '@init/analytics.ts'; + const WEBAPP_SEARCH_PER_PAGE = 20; export function getMissingChannelsFromPosts(posts: RelationOneToOne): ActionFunc { return async (dispatch: DispatchFunc, getState: GetStateFunc) => { @@ -210,7 +212,7 @@ export function getRecentMentions(): ActionFunc { const terms = termKeys.map(({key}) => key).join(' ').trim() + ' '; - Client4.trackEvent('api', 'api_posts_search_mention'); + analytics.trackAPI('api_posts_search_mention'); posts = await Client4.searchPosts(teamId, terms, true); const profilesAndStatuses = getProfilesAndStatusesForPosts(posts.posts, dispatch, getState); diff --git a/app/mm-redux/actions/users.ts b/app/mm-redux/actions/users.ts index 46317f2d4..eea18eddd 100644 --- a/app/mm-redux/actions/users.ts +++ b/app/mm-redux/actions/users.ts @@ -22,6 +22,8 @@ import {logError} from './errors'; import {bindClientFunc, forceLogoutIfNecessary, debounce} from './helpers'; import {getMyPreferences, makeDirectChannelVisibleIfNecessary, makeGroupMessageVisibleIfNecessary} from './preferences'; import {Dictionary} from '@mm-redux/types/utilities'; +import {analytics} from '@init/analytics.ts'; + export function checkMfa(loginId: string): ActionFunc { return async (dispatch: DispatchFunc) => { dispatch({type: UserTypes.CHECK_MFA_REQUEST, data: null}); @@ -126,8 +128,8 @@ function completeLogin(data: UserProfile): ActionFunc { data, }); - Client4.setUserId(data.id); - Client4.setUserRoles(data.roles); + analytics.setUserId(data.id); + analytics.setUserRoles(data.roles); let teamMembers; try { @@ -231,11 +233,11 @@ export function loadMe(): ActionFunc { const {currentUserId} = getState().entities.users; const user = getState().entities.users.profiles[currentUserId]; if (currentUserId) { - Client4.setUserId(currentUserId); + analytics.setUserId(currentUserId); } if (user) { - Client4.setUserRoles(user.roles); + analytics.setUserRoles(user.roles); } return {data: true}; diff --git a/app/mm-redux/client/client4.ts b/app/mm-redux/client/client4.ts index 597a629e4..08b31a0f7 100644 --- a/app/mm-redux/client/client4.ts +++ b/app/mm-redux/client/client4.ts @@ -1,10 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {analytics, context} from '@init/analytics.ts'; +import {analytics} from '@init/analytics.ts'; import {buildQueryString, isMinimumServerVersion} from '@mm-redux/utils/helpers'; import {cleanUrlForLogging} from '@mm-redux/utils/sentry'; -import {isSystemAdmin} from '@mm-redux/utils/user_utils'; import {UserProfile, UserStatus} from '@mm-redux/types/users'; import {Team} from '@mm-redux/types/teams'; import {Channel, ChannelModerationPatch} from '@mm-redux/types/channels'; @@ -49,14 +48,12 @@ export default class Client4 { userAgent: string|null = null; enableLogging = false; defaultHeaders: {[x: string]: string} = {}; - userId = ''; diagnosticId = ''; includeCookies = true; translations = { connectionError: 'There appears to be a problem with your internet connection.', unknownError: 'We received an unexpected status code from the server.', }; - userRoles?: string; getUrl() { return this.url; @@ -101,14 +98,6 @@ export default class Client4 { this.includeCookies = include; } - setUserId(userId: string) { - this.userId = userId; - } - - setUserRoles(roles: string) { - this.userRoles = roles; - } - setDiagnosticId(diagnosticId: string) { this.diagnosticId = diagnosticId; } @@ -345,7 +334,7 @@ export default class Client4 { // User Routes createUser = async (user: UserProfile, token: string, inviteId: string) => { - this.trackEvent('api', 'api_users_create'); + analytics.trackAPI('api_users_create'); const queryParams: any = {}; @@ -371,7 +360,7 @@ export default class Client4 { } patchUser = async (userPatch: Partial & {id: string}) => { - this.trackEvent('api', 'api_users_patch'); + analytics.trackAPI('api_users_patch'); return this.doFetch( `${this.getUserRoute(userPatch.id)}/patch`, @@ -380,7 +369,7 @@ export default class Client4 { } updateUser = async (user: UserProfile) => { - this.trackEvent('api', 'api_users_update'); + analytics.trackAPI('api_users_update'); return this.doFetch( `${this.getUserRoute(user.id)}`, @@ -389,7 +378,7 @@ export default class Client4 { } promoteGuestToUser = async (userId: string) => { - this.trackEvent('api', 'api_users_promote_guest_to_user'); + analytics.trackAPI('api_users_promote_guest_to_user'); return this.doFetch( `${this.getUserRoute(userId)}/promote`, @@ -398,7 +387,7 @@ export default class Client4 { } demoteUserToGuest = async (userId: string) => { - this.trackEvent('api', 'api_users_demote_user_to_guest'); + analytics.trackAPI('api_users_demote_user_to_guest'); return this.doFetch( `${this.getUserRoute(userId)}/demote`, @@ -407,7 +396,7 @@ export default class Client4 { } updateUserRoles = async (userId: string, roles: string) => { - this.trackEvent('api', 'api_users_update_roles'); + analytics.trackAPI('api_users_update_roles'); return this.doFetch( `${this.getUserRoute(userId)}/roles`, @@ -430,7 +419,7 @@ export default class Client4 { } updateUserPassword = async (userId: string, currentPassword: string, newPassword: string) => { - this.trackEvent('api', 'api_users_newpassword'); + analytics.trackAPI('api_users_newpassword'); return this.doFetch( `${this.getUserRoute(userId)}/password`, @@ -439,7 +428,7 @@ export default class Client4 { } resetUserPassword = async (token: string, newPassword: string) => { - this.trackEvent('api', 'api_users_reset_password'); + analytics.trackAPI('api_users_reset_password'); return this.doFetch( `${this.getUsersRoute()}/password/reset`, @@ -448,7 +437,7 @@ export default class Client4 { } getKnownUsers = async () => { - this.trackEvent('api', 'api_get_known_users'); + analytics.trackAPI('api_get_known_users'); return this.doFetch( `${this.getUsersRoute()}/known`, @@ -457,7 +446,7 @@ export default class Client4 { } sendPasswordResetEmail = async (email: string) => { - this.trackEvent('api', 'api_users_send_password_reset'); + analytics.trackAPI('api_users_send_password_reset'); return this.doFetch( `${this.getUsersRoute()}/password/reset/send`, @@ -466,7 +455,7 @@ export default class Client4 { } updateUserActive = async (userId: string, active: boolean) => { - this.trackEvent('api', 'api_users_update_active'); + analytics.trackAPI('api_users_update_active'); return this.doFetch( `${this.getUserRoute(userId)}/active`, @@ -475,7 +464,7 @@ export default class Client4 { } uploadProfileImage = async (userId: string, imageData: any) => { - this.trackEvent('api', 'api_users_update_profile_picture'); + analytics.trackAPI('api_users_update_profile_picture'); const formData = new FormData(); formData.append('image', imageData); @@ -497,7 +486,7 @@ export default class Client4 { }; setDefaultProfileImage = async (userId: string) => { - this.trackEvent('api', 'api_users_set_default_profile_picture'); + analytics.trackAPI('api_users_set_default_profile_picture'); return this.doFetch( `${this.getUserRoute(userId)}/image`, @@ -541,10 +530,10 @@ export default class Client4 { } login = async (loginId: string, password: string, token = '', deviceId = '', ldapOnly = false) => { - this.trackEvent('api', 'api_users_login'); + analytics.trackAPI('api_users_login'); if (ldapOnly) { - this.trackEvent('api', 'api_users_login_ldap'); + analytics.trackAPI('api_users_login_ldap'); } const body: any = { @@ -567,7 +556,7 @@ export default class Client4 { }; loginById = async (id: string, password: string, token = '', deviceId = '') => { - this.trackEvent('api', 'api_users_login'); + analytics.trackAPI('api_users_login'); const body: any = { device_id: deviceId, id, @@ -584,7 +573,7 @@ export default class Client4 { }; logout = async () => { - this.trackEvent('api', 'api_users_logout'); + analytics.trackAPI('api_users_logout'); const {response} = await this.doFetchWithResponse( `${this.getUsersRoute()}/logout`, @@ -601,7 +590,7 @@ export default class Client4 { }; getProfiles = async (page = 0, perPage = PER_PAGE_DEFAULT, options = {}) => { - this.trackEvent('api', 'api_profiles_get'); + analytics.trackAPI('api_profiles_get'); return this.doFetch( `${this.getUsersRoute()}${buildQueryString({page, per_page: perPage, ...options})}`, @@ -610,7 +599,7 @@ export default class Client4 { }; getProfilesByIds = async (userIds: string[], options = {}) => { - this.trackEvent('api', 'api_profiles_get_by_ids'); + analytics.trackAPI('api_profiles_get_by_ids'); return this.doFetch( `${this.getUsersRoute()}/ids${buildQueryString(options)}`, @@ -619,7 +608,7 @@ export default class Client4 { }; getProfilesByUsernames = async (usernames: string[]) => { - this.trackEvent('api', 'api_profiles_get_by_usernames'); + analytics.trackAPI('api_profiles_get_by_usernames'); return this.doFetch( `${this.getUsersRoute()}/usernames`, @@ -628,7 +617,7 @@ export default class Client4 { }; getProfilesInTeam = async (teamId: string, page = 0, perPage = PER_PAGE_DEFAULT, sort = '', options = {}) => { - this.trackEvent('api', 'api_profiles_get_in_team', {team_id: teamId, sort}); + analytics.trackAPI('api_profiles_get_in_team', {team_id: teamId, sort}); return this.doFetch( `${this.getUsersRoute()}${buildQueryString({...options, in_team: teamId, page, per_page: perPage, sort})}`, @@ -637,7 +626,7 @@ export default class Client4 { }; getProfilesNotInTeam = async (teamId: string, groupConstrained: boolean, page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_profiles_get_not_in_team', {team_id: teamId, group_constrained: groupConstrained}); + analytics.trackAPI('api_profiles_get_not_in_team', {team_id: teamId, group_constrained: groupConstrained}); const queryStringObj: any = {not_in_team: teamId, page, per_page: perPage}; if (groupConstrained) { @@ -651,7 +640,7 @@ export default class Client4 { }; getProfilesWithoutTeam = async (page = 0, perPage = PER_PAGE_DEFAULT, options = {}) => { - this.trackEvent('api', 'api_profiles_get_without_team'); + analytics.trackAPI('api_profiles_get_without_team'); return this.doFetch( `${this.getUsersRoute()}${buildQueryString({...options, without_team: 1, page, per_page: perPage})}`, @@ -660,7 +649,7 @@ export default class Client4 { }; getProfilesInChannel = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT, sort = '') => { - this.trackEvent('api', 'api_profiles_get_in_channel', {channel_id: channelId}); + analytics.trackAPI('api_profiles_get_in_channel', {channel_id: channelId}); const serverVersion = this.getServerVersion(); let queryStringObj; @@ -676,7 +665,7 @@ export default class Client4 { }; getProfilesInGroupChannels = async (channelsIds: string[]) => { - this.trackEvent('api', 'api_profiles_get_in_group_channels', {channelsIds}); + analytics.trackAPI('api_profiles_get_in_group_channels', {channelsIds}); return this.doFetch( `${this.getUsersRoute()}/group_channels`, @@ -685,7 +674,7 @@ export default class Client4 { }; getProfilesNotInChannel = async (teamId: string, channelId: string, groupConstrained: boolean, page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_profiles_get_not_in_channel', {team_id: teamId, channel_id: channelId, group_constrained: groupConstrained}); + analytics.trackAPI('api_profiles_get_not_in_channel', {team_id: teamId, channel_id: channelId, group_constrained: groupConstrained}); const queryStringObj: any = {in_team: teamId, not_in_channel: channelId, page, per_page: perPage}; if (groupConstrained) { @@ -807,7 +796,7 @@ export default class Client4 { }; searchUsers = (term: string, options: any) => { - this.trackEvent('api', 'api_search_users'); + analytics.trackAPI('api_search_users'); return this.doFetch( `${this.getUsersRoute()}/search`, @@ -837,7 +826,7 @@ export default class Client4 { }; switchEmailToOAuth = async (service: string, email: string, password: string, mfaCode = '') => { - this.trackEvent('api', 'api_users_email_to_oauth'); + analytics.trackAPI('api_users_email_to_oauth'); return this.doFetch( `${this.getUsersRoute()}/login/switch`, @@ -846,7 +835,7 @@ export default class Client4 { }; switchOAuthToEmail = async (currentService: string, email: string, password: string) => { - this.trackEvent('api', 'api_users_oauth_to_email'); + analytics.trackAPI('api_users_oauth_to_email'); return this.doFetch( `${this.getUsersRoute()}/login/switch`, @@ -855,7 +844,7 @@ export default class Client4 { }; switchEmailToLdap = async (email: string, emailPassword: string, ldapId: string, ldapPassword: string, mfaCode = '') => { - this.trackEvent('api', 'api_users_email_to_ldap'); + analytics.trackAPI('api_users_email_to_ldap'); return this.doFetch( `${this.getUsersRoute()}/login/switch`, @@ -864,7 +853,7 @@ export default class Client4 { }; switchLdapToEmail = async (ldapPassword: string, email: string, emailPassword: string, mfaCode = '') => { - this.trackEvent('api', 'api_users_ldap_to_email'); + analytics.trackAPI('api_users_ldap_to_email'); return this.doFetch( `${this.getUsersRoute()}/login/switch`, @@ -894,7 +883,7 @@ export default class Client4 { } createUserAccessToken = async (userId: string, description: string) => { - this.trackEvent('api', 'api_users_create_access_token'); + analytics.trackAPI('api_users_create_access_token'); return this.doFetch( `${this.getUserRoute(userId)}/tokens`, @@ -924,7 +913,7 @@ export default class Client4 { } revokeUserAccessToken = async (tokenId: string) => { - this.trackEvent('api', 'api_users_revoke_access_token'); + analytics.trackAPI('api_users_revoke_access_token'); return this.doFetch( `${this.getUsersRoute()}/tokens/revoke`, @@ -949,7 +938,7 @@ export default class Client4 { // Team Routes createTeam = async (team: Team) => { - this.trackEvent('api', 'api_teams_create'); + analytics.trackAPI('api_teams_create'); return this.doFetch( `${this.getTeamsRoute()}`, @@ -958,7 +947,7 @@ export default class Client4 { }; deleteTeam = async (teamId: string) => { - this.trackEvent('api', 'api_teams_delete'); + analytics.trackAPI('api_teams_delete'); return this.doFetch( `${this.getTeamRoute(teamId)}`, @@ -967,7 +956,7 @@ export default class Client4 { }; updateTeam = async (team: Team) => { - this.trackEvent('api', 'api_teams_update_name', {team_id: team.id}); + analytics.trackAPI('api_teams_update_name', {team_id: team.id}); return this.doFetch( `${this.getTeamRoute(team.id)}`, @@ -976,7 +965,7 @@ export default class Client4 { }; patchTeam = async (team: Partial & {id: string}) => { - this.trackEvent('api', 'api_teams_patch_name', {team_id: team.id}); + analytics.trackAPI('api_teams_patch_name', {team_id: team.id}); return this.doFetch( `${this.getTeamRoute(team.id)}/patch`, @@ -985,7 +974,7 @@ export default class Client4 { }; regenerateTeamInviteId = async (teamId: string) => { - this.trackEvent('api', 'api_teams_regenerate_invite_id', {team_id: teamId}); + analytics.trackAPI('api_teams_regenerate_invite_id', {team_id: teamId}); return this.doFetch( `${this.getTeamRoute(teamId)}/regenerate_invite_id`, @@ -996,7 +985,7 @@ export default class Client4 { updateTeamScheme = async (teamId: string, schemeId: string) => { const patch = {scheme_id: schemeId}; - this.trackEvent('api', 'api_teams_update_scheme', {team_id: teamId, ...patch}); + analytics.trackAPI('api_teams_update_scheme', {team_id: teamId, ...patch}); return this.doFetch( `${this.getTeamSchemeRoute(teamId)}`, @@ -1019,7 +1008,7 @@ export default class Client4 { }; searchTeams = (term: string, page?: number, perPage?: number) => { - this.trackEvent('api', 'api_search_teams'); + analytics.trackAPI('api_search_teams'); return this.doFetch( `${this.getTeamsRoute()}/search`, @@ -1035,7 +1024,7 @@ export default class Client4 { }; getTeamByName = async (teamName: string) => { - this.trackEvent('api', 'api_teams_get_team_by_name'); + analytics.trackAPI('api_teams_get_team_by_name'); return this.doFetch( this.getTeamNameRoute(teamName), @@ -1100,7 +1089,7 @@ export default class Client4 { }; addToTeam = async (teamId: string, userId: string) => { - this.trackEvent('api', 'api_teams_invite_members', {team_id: teamId}); + analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); const member = {user_id: userId, team_id: teamId}; return this.doFetch( @@ -1110,7 +1099,7 @@ export default class Client4 { }; addToTeamFromInvite = async (token = '', inviteId = '') => { - this.trackEvent('api', 'api_teams_invite_members'); + analytics.trackAPI('api_teams_invite_members'); const query = buildQueryString({token, invite_id: inviteId}); return this.doFetch( @@ -1120,7 +1109,7 @@ export default class Client4 { }; addUsersToTeam = async (teamId: string, userIds: string[]) => { - this.trackEvent('api', 'api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); + analytics.trackAPI('api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); const members: any = []; userIds.forEach((id) => members.push({team_id: teamId, user_id: id})); @@ -1131,7 +1120,7 @@ export default class Client4 { }; addUsersToTeamGracefully = async (teamId: string, userIds: string[]) => { - this.trackEvent('api', 'api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); + analytics.trackAPI('api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); const members: any = []; userIds.forEach((id) => members.push({team_id: teamId, user_id: id})); @@ -1150,7 +1139,7 @@ export default class Client4 { }; removeFromTeam = async (teamId: string, userId: string) => { - this.trackEvent('api', 'api_teams_remove_members', {team_id: teamId}); + analytics.trackAPI('api_teams_remove_members', {team_id: teamId}); return this.doFetch( `${this.getTeamMemberRoute(teamId, userId)}`, @@ -1187,7 +1176,7 @@ export default class Client4 { }; updateTeamMemberRoles = async (teamId: string, userId: string, roles: string[]) => { - this.trackEvent('api', 'api_teams_update_member_roles', {team_id: teamId}); + analytics.trackAPI('api_teams_update_member_roles', {team_id: teamId}); return this.doFetch( `${this.getTeamMemberRoute(teamId, userId)}/roles`, @@ -1196,7 +1185,7 @@ export default class Client4 { }; sendEmailInvitesToTeam = async (teamId: string, emails: string[]) => { - this.trackEvent('api', 'api_teams_invite_members', {team_id: teamId}); + analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); return this.doFetch( `${this.getTeamRoute(teamId)}/invite/email`, @@ -1205,7 +1194,7 @@ export default class Client4 { }; sendEmailGuestInvitesToChannels = async (teamId: string, channelIds: string[], emails: string[], message: string) => { - this.trackEvent('api', 'api_teams_invite_guests', {team_id: teamId, channel_ids: channelIds}); + analytics.trackAPI('api_teams_invite_guests', {team_id: teamId, channel_ids: channelIds}); return this.doFetch( `${this.getTeamRoute(teamId)}/invite-guests/email`, @@ -1214,7 +1203,7 @@ export default class Client4 { }; sendEmailInvitesToTeamGracefully = async (teamId: string, emails: string[]) => { - this.trackEvent('api', 'api_teams_invite_members', {team_id: teamId}); + analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); return this.doFetch( `${this.getTeamRoute(teamId)}/invite/email?graceful=true`, @@ -1223,7 +1212,7 @@ export default class Client4 { }; sendEmailGuestInvitesToChannelsGracefully = async (teamId: string, channelIds: string[], emails: string[], message: string) => { - this.trackEvent('api', 'api_teams_invite_guests', {team_id: teamId, channel_ids: channelIds}); + analytics.trackAPI('api_teams_invite_guests', {team_id: teamId, channel_ids: channelIds}); return this.doFetch( `${this.getTeamRoute(teamId)}/invite-guests/email?graceful=true`, @@ -1264,7 +1253,7 @@ export default class Client4 { }; setTeamIcon = async (teamId: string, imageData: any) => { - this.trackEvent('api', 'api_team_set_team_icon'); + analytics.trackAPI('api_team_set_team_icon'); const formData = new FormData(); formData.append('image', imageData); @@ -1287,7 +1276,7 @@ export default class Client4 { }; removeTeamIcon = async (teamId: string) => { - this.trackEvent('api', 'api_team_remove_team_icon'); + analytics.trackAPI('api_team_remove_team_icon'); return this.doFetch( `${this.getTeamRoute(teamId)}/image`, @@ -1320,7 +1309,7 @@ export default class Client4 { }; createChannel = async (channel: Channel) => { - this.trackEvent('api', 'api_channels_create', {team_id: channel.team_id}); + analytics.trackAPI('api_channels_create', {team_id: channel.team_id}); return this.doFetch( `${this.getChannelsRoute()}`, @@ -1329,7 +1318,7 @@ export default class Client4 { }; createDirectChannel = async (userIds: string[]) => { - this.trackEvent('api', 'api_channels_create_direct'); + analytics.trackAPI('api_channels_create_direct'); return this.doFetch( `${this.getChannelsRoute()}/direct`, @@ -1338,7 +1327,7 @@ export default class Client4 { }; createGroupChannel = async (userIds: string[]) => { - this.trackEvent('api', 'api_channels_create_group'); + analytics.trackAPI('api_channels_create_group'); return this.doFetch( `${this.getChannelsRoute()}/group`, @@ -1347,7 +1336,7 @@ export default class Client4 { }; deleteChannel = async (channelId: string) => { - this.trackEvent('api', 'api_channels_delete', {channel_id: channelId}); + analytics.trackAPI('api_channels_delete', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}`, @@ -1356,7 +1345,7 @@ export default class Client4 { }; unarchiveChannel = async (channelId: string) => { - this.trackEvent('api', 'api_channels_unarchive', {channel_id: channelId}); + analytics.trackAPI('api_channels_unarchive', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}/restore`, @@ -1365,7 +1354,7 @@ export default class Client4 { }; updateChannel = async (channel: Channel) => { - this.trackEvent('api', 'api_channels_update', {channel_id: channel.id}); + analytics.trackAPI('api_channels_update', {channel_id: channel.id}); return this.doFetch( `${this.getChannelRoute(channel.id)}`, @@ -1374,7 +1363,7 @@ export default class Client4 { }; convertChannelToPrivate = async (channelId: string) => { - this.trackEvent('api', 'api_channels_convert_to_private', {channel_id: channelId}); + analytics.trackAPI('api_channels_convert_to_private', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}/convert`, @@ -1383,7 +1372,7 @@ export default class Client4 { }; updateChannelPrivacy = async (channelId: string, privacy: any) => { - this.trackEvent('api', 'api_channels_update_privacy', {channel_id: channelId, privacy}); + analytics.trackAPI('api_channels_update_privacy', {channel_id: channelId, privacy}); return this.doFetch( `${this.getChannelRoute(channelId)}/privacy`, @@ -1392,7 +1381,7 @@ export default class Client4 { }; patchChannel = async (channelId: string, channelPatch: Partial) => { - this.trackEvent('api', 'api_channels_patch', {channel_id: channelId}); + analytics.trackAPI('api_channels_patch', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}/patch`, @@ -1401,7 +1390,7 @@ export default class Client4 { }; updateChannelNotifyProps = async (props: any) => { - this.trackEvent('api', 'api_users_update_channel_notifications', {channel_id: props.channel_id}); + analytics.trackAPI('api_users_update_channel_notifications', {channel_id: props.channel_id}); return this.doFetch( `${this.getChannelMemberRoute(props.channel_id, props.user_id)}/notify_props`, @@ -1412,7 +1401,7 @@ export default class Client4 { updateChannelScheme = async (channelId: string, schemeId: string) => { const patch = {scheme_id: schemeId}; - this.trackEvent('api', 'api_channels_update_scheme', {channel_id: channelId, ...patch}); + analytics.trackAPI('api_channels_update_scheme', {channel_id: channelId, ...patch}); return this.doFetch( `${this.getChannelSchemeRoute(channelId)}`, @@ -1421,7 +1410,7 @@ export default class Client4 { }; getChannel = async (channelId: string) => { - this.trackEvent('api', 'api_channel_get', {channel_id: channelId}); + analytics.trackAPI('api_channel_get', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}`, @@ -1437,7 +1426,7 @@ export default class Client4 { }; getChannelByNameAndTeamName = async (teamName: string, channelName: string, includeDeleted = false) => { - this.trackEvent('api', 'api_channel_get_by_name_and_teamName', {channel_name: channelName, team_name: teamName, include_deleted: includeDeleted}); + analytics.trackAPI('api_channel_get_by_name_and_teamName', {channel_name: channelName, team_name: teamName, include_deleted: includeDeleted}); return this.doFetch( `${this.getTeamNameRoute(teamName)}/channels/name/${channelName}?include_deleted=${includeDeleted}`, @@ -1508,7 +1497,7 @@ export default class Client4 { }; addToChannel = async (userId: string, channelId: string, postRootId = '') => { - this.trackEvent('api', 'api_channels_add_member', {channel_id: channelId}); + analytics.trackAPI('api_channels_add_member', {channel_id: channelId}); const member = {user_id: userId, channel_id: channelId, post_root_id: postRootId}; return this.doFetch( @@ -1518,7 +1507,7 @@ export default class Client4 { }; removeFromChannel = async (userId: string, channelId: string) => { - this.trackEvent('api', 'api_channels_remove_member', {channel_id: channelId}); + analytics.trackAPI('api_channels_remove_member', {channel_id: channelId}); return this.doFetch( `${this.getChannelMemberRoute(channelId, userId)}`, @@ -1629,10 +1618,10 @@ export default class Client4 { // Post Routes createPost = async (post: Post) => { - this.trackEvent('api', 'api_posts_create', {channel_id: post.channel_id}); + analytics.trackAPI('api_posts_create', {channel_id: post.channel_id}); if (post.root_id != null && post.root_id !== '') { - this.trackEvent('api', 'api_posts_replied', {channel_id: post.channel_id}); + analytics.trackAPI('api_posts_replied', {channel_id: post.channel_id}); } return this.doFetch( @@ -1642,7 +1631,7 @@ export default class Client4 { }; updatePost = async (post: Post) => { - this.trackEvent('api', 'api_posts_update', {channel_id: post.channel_id}); + analytics.trackAPI('api_posts_update', {channel_id: post.channel_id}); return this.doFetch( `${this.getPostRoute(post.id)}`, @@ -1658,7 +1647,7 @@ export default class Client4 { }; patchPost = async (postPatch: Partial & {id: string}) => { - this.trackEvent('api', 'api_posts_patch', {channel_id: postPatch.channel_id}); + analytics.trackAPI('api_posts_patch', {channel_id: postPatch.channel_id}); return this.doFetch( `${this.getPostRoute(postPatch.id)}/patch`, @@ -1667,7 +1656,7 @@ export default class Client4 { }; deletePost = async (postId: string) => { - this.trackEvent('api', 'api_posts_delete'); + analytics.trackAPI('api_posts_delete'); return this.doFetch( `${this.getPostRoute(postId)}`, @@ -1704,7 +1693,7 @@ export default class Client4 { }; getPostsBefore = async (channelId: string, postId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_posts_get_before', {channel_id: channelId}); + analytics.trackAPI('api_posts_get_before', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}/posts${buildQueryString({before: postId, page, per_page: perPage})}`, @@ -1713,7 +1702,7 @@ export default class Client4 { }; getPostsAfter = async (channelId: string, postId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_posts_get_after', {channel_id: channelId}); + analytics.trackAPI('api_posts_get_after', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}/posts${buildQueryString({after: postId, page, per_page: perPage})}`, @@ -1729,7 +1718,7 @@ export default class Client4 { }; getFlaggedPosts = async (userId: string, channelId = '', teamId = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_posts_get_flagged', {team_id: teamId}); + analytics.trackAPI('api_posts_get_flagged', {team_id: teamId}); return this.doFetch( `${this.getUserRoute(userId)}/posts/flagged${buildQueryString({channel_id: channelId, team_id: teamId, page, per_page: perPage})}`, @@ -1738,7 +1727,7 @@ export default class Client4 { }; getPinnedPosts = async (channelId: string) => { - this.trackEvent('api', 'api_posts_get_pinned', {channel_id: channelId}); + analytics.trackAPI('api_posts_get_pinned', {channel_id: channelId}); return this.doFetch( `${this.getChannelRoute(channelId)}/pinned`, {method: 'get'}, @@ -1746,7 +1735,7 @@ export default class Client4 { }; markPostAsUnread = async (userId: string, postId: string) => { - this.trackEvent('api', 'api_post_set_unread_post'); + analytics.trackAPI('api_post_set_unread_post'); return this.doFetch( `${this.getUserRoute(userId)}/posts/${postId}/set_unread`, @@ -1755,7 +1744,7 @@ export default class Client4 { } pinPost = async (postId: string) => { - this.trackEvent('api', 'api_posts_pin'); + analytics.trackAPI('api_posts_pin'); return this.doFetch( `${this.getPostRoute(postId)}/pin`, @@ -1764,7 +1753,7 @@ export default class Client4 { }; unpinPost = async (postId: string) => { - this.trackEvent('api', 'api_posts_unpin'); + analytics.trackAPI('api_posts_unpin'); return this.doFetch( `${this.getPostRoute(postId)}/unpin`, @@ -1773,7 +1762,7 @@ export default class Client4 { }; addReaction = async (userId: string, postId: string, emojiName: string) => { - this.trackEvent('api', 'api_reactions_save', {post_id: postId}); + analytics.trackAPI('api_reactions_save', {post_id: postId}); return this.doFetch( `${this.getReactionsRoute()}`, @@ -1782,7 +1771,7 @@ export default class Client4 { }; removeReaction = async (userId: string, postId: string, emojiName: string) => { - this.trackEvent('api', 'api_reactions_delete', {post_id: postId}); + analytics.trackAPI('api_reactions_delete', {post_id: postId}); return this.doFetch( `${this.getUserRoute(userId)}/posts/${postId}/reactions/${emojiName}`, @@ -1798,7 +1787,7 @@ export default class Client4 { }; searchPostsWithParams = async (teamId: string, params: any) => { - this.trackEvent('api', 'api_posts_search', {team_id: teamId}); + analytics.trackAPI('api_posts_search', {team_id: teamId}); return this.doFetch( `${this.getTeamRoute(teamId)}/posts/search`, @@ -1823,9 +1812,9 @@ export default class Client4 { doPostActionWithCookie = async (postId: string, actionId: string, actionCookie: string, selectedOption = '') => { if (selectedOption) { - this.trackEvent('api', 'api_interactive_messages_menu_selected'); + analytics.trackAPI('api_interactive_messages_menu_selected'); } else { - this.trackEvent('api', 'api_interactive_messages_button_clicked'); + analytics.trackAPI('api_interactive_messages_button_clicked'); } const msg: any = { @@ -1870,7 +1859,7 @@ export default class Client4 { } uploadFile = async (fileFormData: any, formBoundary: string) => { - this.trackEvent('api', 'api_files_upload'); + analytics.trackAPI('api_files_upload'); const request: any = { method: 'post', body: fileFormData, @@ -1978,7 +1967,7 @@ export default class Client4 { // Integration Routes createIncomingWebhook = async (hook: IncomingWebhook) => { - this.trackEvent('api', 'api_integrations_created', {team_id: hook.team_id}); + analytics.trackAPI('api_integrations_created', {team_id: hook.team_id}); return this.doFetch( `${this.getIncomingHooksRoute()}`, @@ -2010,7 +1999,7 @@ export default class Client4 { }; removeIncomingWebhook = async (hookId: string) => { - this.trackEvent('api', 'api_integrations_deleted'); + analytics.trackAPI('api_integrations_deleted'); return this.doFetch( `${this.getIncomingHookRoute(hookId)}`, @@ -2019,7 +2008,7 @@ export default class Client4 { }; updateIncomingWebhook = async (hook: IncomingWebhook) => { - this.trackEvent('api', 'api_integrations_updated', {team_id: hook.team_id}); + analytics.trackAPI('api_integrations_updated', {team_id: hook.team_id}); return this.doFetch( `${this.getIncomingHookRoute(hook.id)}`, @@ -2028,7 +2017,7 @@ export default class Client4 { }; createOutgoingWebhook = async (hook: OutgoingWebhook) => { - this.trackEvent('api', 'api_integrations_created', {team_id: hook.team_id}); + analytics.trackAPI('api_integrations_created', {team_id: hook.team_id}); return this.doFetch( `${this.getOutgoingHooksRoute()}`, @@ -2064,7 +2053,7 @@ export default class Client4 { }; removeOutgoingWebhook = async (hookId: string) => { - this.trackEvent('api', 'api_integrations_deleted'); + analytics.trackAPI('api_integrations_deleted'); return this.doFetch( `${this.getOutgoingHookRoute(hookId)}`, @@ -2073,7 +2062,7 @@ export default class Client4 { }; updateOutgoingWebhook = async (hook: OutgoingWebhook) => { - this.trackEvent('api', 'api_integrations_updated', {team_id: hook.team_id}); + analytics.trackAPI('api_integrations_updated', {team_id: hook.team_id}); return this.doFetch( `${this.getOutgoingHookRoute(hook.id)}`, @@ -2110,7 +2099,7 @@ export default class Client4 { }; executeCommand = async (command: Command, commandArgs = {}) => { - this.trackEvent('api', 'api_integrations_used'); + analytics.trackAPI('api_integrations_used'); return this.doFetch( `${this.getCommandsRoute()}/execute`, @@ -2119,7 +2108,7 @@ export default class Client4 { }; addCommand = async (command: Command) => { - this.trackEvent('api', 'api_integrations_created'); + analytics.trackAPI('api_integrations_created'); return this.doFetch( `${this.getCommandsRoute()}`, @@ -2128,7 +2117,7 @@ export default class Client4 { }; editCommand = async (command: Command) => { - this.trackEvent('api', 'api_integrations_created'); + analytics.trackAPI('api_integrations_created'); return this.doFetch( `${this.getCommandsRoute()}/${command.id}`, @@ -2144,7 +2133,7 @@ export default class Client4 { }; deleteCommand = async (id: string) => { - this.trackEvent('api', 'api_integrations_deleted'); + analytics.trackAPI('api_integrations_deleted'); return this.doFetch( `${this.getCommandsRoute()}/${id}`, @@ -2153,7 +2142,7 @@ export default class Client4 { }; createOAuthApp = async (app: OAuthApp) => { - this.trackEvent('api', 'api_apps_register'); + analytics.trackAPI('api_apps_register'); return this.doFetch( `${this.getOAuthAppsRoute()}`, @@ -2190,7 +2179,7 @@ export default class Client4 { }; deleteOAuthApp = async (appId: string) => { - this.trackEvent('api', 'api_apps_delete'); + analytics.trackAPI('api_apps_delete'); return this.doFetch( `${this.getOAuthAppRoute(appId)}`, @@ -2206,7 +2195,7 @@ export default class Client4 { }; submitInteractiveDialog = async (data: DialogSubmission) => { - this.trackEvent('api', 'api_interactive_messages_dialog_submitted'); + analytics.trackAPI('api_interactive_messages_dialog_submitted'); return this.doFetch( `${this.getBaseRoute()}/actions/dialogs/submit`, {method: 'post', body: JSON.stringify(data)}, @@ -2216,7 +2205,7 @@ export default class Client4 { // Emoji Routes createCustomEmoji = async (emoji: CustomEmoji, imageData: any) => { - this.trackEvent('api', 'api_emoji_custom_add'); + analytics.trackAPI('api_emoji_custom_add'); const formData = new FormData(); formData.append('image', imageData); @@ -2260,7 +2249,7 @@ export default class Client4 { }; deleteCustomEmoji = async (emojiId: string) => { - this.trackEvent('api', 'api_emoji_custom_delete'); + analytics.trackAPI('api_emoji_custom_delete'); return this.doFetch( `${this.getEmojiRoute(emojiId)}`, @@ -2597,7 +2586,7 @@ export default class Client4 { }; uploadLicense = async (fileData: any) => { - this.trackEvent('api', 'api_license_upload'); + analytics.trackAPI('api_license_upload'); const formData = new FormData(); formData.append('license', fileData); @@ -2673,7 +2662,7 @@ export default class Client4 { }; createScheme = async (scheme: Scheme) => { - this.trackEvent('api', 'api_schemes_create'); + analytics.trackAPI('api_schemes_create'); return this.doFetch( `${this.getSchemesRoute()}`, @@ -2689,7 +2678,7 @@ export default class Client4 { }; deleteScheme = async (schemeId: string) => { - this.trackEvent('api', 'api_schemes_delete'); + analytics.trackAPI('api_schemes_delete'); return this.doFetch( `${this.getSchemesRoute()}/${schemeId}`, @@ -2698,7 +2687,7 @@ export default class Client4 { }; patchScheme = async (schemeId: string, schemePatch: Partial) => { - this.trackEvent('api', 'api_schemes_patch', {scheme_id: schemeId}); + analytics.trackAPI('api_schemes_patch', {scheme_id: schemeId}); return this.doFetch( `${this.getSchemesRoute()}/${schemeId}/patch`, @@ -2723,7 +2712,7 @@ export default class Client4 { // Plugin Routes - EXPERIMENTAL - SUBJECT TO CHANGE uploadPlugin = async (fileData: any, force = false) => { - this.trackEvent('api', 'api_plugin_upload'); + analytics.trackAPI('api_plugin_upload'); const formData = new FormData(); if (force) { @@ -2749,7 +2738,7 @@ export default class Client4 { }; installPluginFromUrl = async (pluginDownloadUrl: string, force = false) => { - this.trackEvent('api', 'api_install_plugin'); + analytics.trackAPI('api_install_plugin'); const queryParams = {plugin_download_url: pluginDownloadUrl, force}; @@ -2774,7 +2763,7 @@ export default class Client4 { } installMarketplacePlugin = async (id: string, version: string) => { - this.trackEvent('api', 'api_install_marketplace_plugin'); + analytics.trackAPI('api_install_marketplace_plugin'); return this.doFetch( `${this.getPluginsMarketplaceRoute()}`, @@ -2876,7 +2865,7 @@ export default class Client4 { } getGroupsNotAssociatedToTeam = async (teamID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_groups_get_not_associated_to_team', {team_id: teamID}); + analytics.trackAPI('api_groups_get_not_associated_to_team', {team_id: teamID}); return this.doFetch( `${this.getBaseRoute()}/groups${buildQueryString({not_associated_to_team: teamID, page, per_page: perPage, q, include_member_count: true})}`, {method: 'get'}, @@ -2884,7 +2873,7 @@ export default class Client4 { }; getGroupsNotAssociatedToChannel = async (channelID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => { - this.trackEvent('api', 'api_groups_get_not_associated_to_channel', {channel_id: channelID}); + analytics.trackAPI('api_groups_get_not_associated_to_channel', {channel_id: channelID}); return this.doFetch( `${this.getBaseRoute()}/groups${buildQueryString({not_associated_to_channel: channelID, page, per_page: perPage, q, include_member_count: true})}`, {method: 'get'}, @@ -2892,7 +2881,7 @@ export default class Client4 { }; getGroupsAssociatedToTeam = async (teamID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT, filterAllowReference = false) => { - this.trackEvent('api', 'api_groups_get_associated_to_team', {team_id: teamID}); + analytics.trackAPI('api_groups_get_associated_to_team', {team_id: teamID}); return this.doFetch( `${this.getBaseRoute()}/teams/${teamID}/groups${buildQueryString({page, per_page: perPage, q, include_member_count: true, filter_allow_reference: filterAllowReference})}`, @@ -2901,7 +2890,7 @@ export default class Client4 { }; getGroupsAssociatedToChannel = async (channelID: string, q = '', page = 0, perPage = PER_PAGE_DEFAULT, filterAllowReference = false) => { - this.trackEvent('api', 'api_groups_get_associated_to_channel', {channel_id: channelID}); + analytics.trackAPI('api_groups_get_associated_to_channel', {channel_id: channelID}); return this.doFetch( `${this.getBaseRoute()}/channels/${channelID}/groups${buildQueryString({page, per_page: perPage, q, include_member_count: true, filter_allow_reference: filterAllowReference})}`, @@ -3111,25 +3100,6 @@ export default class Client4 { url, }); }; - - trackEvent(category: string, event: string, props?: any) { - if (!analytics) { - return; - } - - const properties = Object.assign({ - category, - type: event, - user_actual_role: this.userRoles && isSystemAdmin(this.userRoles) ? 'system_admin, system_user' : 'system_user', - user_actual_id: this.userId, - }, props); - const options = { - context, - anonymousId: '00000000000000000000000000', - }; - - analytics.track(event, properties, options); - } } function parseAndMergeNestedHeaders(originalHeaders: any) {