Skip to content

Commit

Permalink
fix(analytics): fix analytics hook for expired or logged out (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
olamothe authored Feb 23, 2021
1 parent 7aec1dd commit 1c9964e
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 10 deletions.
27 changes: 25 additions & 2 deletions packages/cli/src/hooks/analytics/analytics.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ jest.mock('@coveord/platform-client');
import {mocked} from 'ts-jest/utils';
import {CoveoAnalyticsClient, IRuntimeEnvironment} from 'coveo.analytics';
import {Configuration, Config} from '../../lib/config/config';
import {AuthenticatedClient} from '../../lib/platform/authenticatedClient';
import {
AuthenticatedClient,
AuthenticationStatus,
getAuthenticationStatus,
} from '../../lib/platform/authenticatedClient';
import hook, {AnalyticsHook} from './analytics';
import {IConfig} from '@oclif/config';
import {PlatformClient} from '@coveord/platform-client';
Expand All @@ -14,6 +18,7 @@ const mockedAnalytics = mocked(CoveoAnalyticsClient);
const mockedConfig = mocked(Config);
const mockedPlatformClient = mocked(PlatformClient);
const mockedAuthenticatedClient = mocked(AuthenticatedClient);
const mockedAuthenticationStatus = mocked(getAuthenticationStatus);

describe('analytics hook', () => {
let sendCustomEvent: jest.Mock;
Expand Down Expand Up @@ -69,7 +74,7 @@ describe('analytics hook', () => {
};

const doMockAuthenticatedClient = () => {
mockedAuthenticatedClient.mockImplementationOnce(
mockedAuthenticatedClient.mockImplementation(
() =>
({
getClient: () =>
Expand All @@ -82,6 +87,9 @@ describe('analytics hook', () => {
cfg: mockedConfig.getMockImplementation()!('./'),
} as AuthenticatedClient)
);
mockedAuthenticationStatus.mockImplementation(() =>
Promise.resolve(AuthenticationStatus.LOGGED_IN)
);
};

beforeEach(() => {
Expand Down Expand Up @@ -212,4 +220,19 @@ describe('analytics hook', () => {
await hook(getAnalyticsHook({}));
expect(sendCustomEvent).not.toHaveBeenCalled();
});

it('should not throw an error when the user is not logged in', async () => {
mockedAuthenticationStatus.mockImplementationOnce(() =>
Promise.resolve(AuthenticationStatus.LOGGED_OUT)
);

await expect(hook(getAnalyticsHook({}))).resolves.not.toThrow();
});

it('should not throw an error when the user is expired', async () => {
mockedAuthenticationStatus.mockImplementationOnce(() =>
Promise.resolve(AuthenticationStatus.EXPIRED)
);
await expect(hook(getAnalyticsHook({}))).resolves.not.toThrow();
});
});
15 changes: 14 additions & 1 deletion packages/cli/src/hooks/analytics/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import {IConfig} from '@oclif/config';
import {CoveoAnalyticsClient} from 'coveo.analytics';
import {WebStorage} from 'coveo.analytics/dist/definitions/storage';
import {Config} from '../../lib/config/config';
import {AuthenticatedClient} from '../../lib/platform/authenticatedClient';
import {
AuthenticatedClient,
AuthenticationStatus,
getAuthenticationStatus,
} from '../../lib/platform/authenticatedClient';

export interface AnalyticsHook {
commandID: string;
Expand All @@ -15,6 +19,10 @@ export interface AnalyticsHook {
const analyticsAPIKey = 'xx01ad67bb-f837-4a3e-8669-16397994a6f2';

const hook = async function (opts: AnalyticsHook) {
if (!(await isLoggedIn())) {
return;
}

const {eventType, eventValue} = identifier(opts);
const {
environment,
Expand Down Expand Up @@ -109,6 +117,11 @@ const storage = (cfg: Config): WebStorage => {
};
};

const isLoggedIn = async () => {
const status = await getAuthenticationStatus();
return status === AuthenticationStatus.LOGGED_IN;
};

export type AnalyticsStatus = 'success' | 'failure';

export const buildAnalyticsHook = (
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/src/lib/decorators/authenticationRequired.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/* eslint-disable @typescript-eslint/no-namespace */
import Command from '@oclif/command';
import {IConfig} from '@oclif/config';
import {AuthenticatedClient} from '../platform/authenticatedClient';
import {
AuthenticationStatus,
getAuthenticationStatus,
} from '../platform/authenticatedClient';

declare global {
namespace NodeJS {
Expand All @@ -20,16 +23,13 @@ export default function AuthenticationRequired() {
) {
const originalRunCommand = descriptor.value!;
descriptor.value = async function () {
const authenticatedClient = new AuthenticatedClient();
const status = await getAuthenticationStatus();

const loggedIn = await authenticatedClient.isLoggedIn();

if (!loggedIn) {
if (status === AuthenticationStatus.LOGGED_OUT) {
target.error('Not currently logged in. Run coveo auth:login first.');
}

const isExpired = await authenticatedClient.isExpired();
if (isExpired) {
if (status === AuthenticationStatus.EXPIRED) {
target.error(
'Authentication token is expired. Run coveo auth:login first.'
);
Expand Down
20 changes: 20 additions & 0 deletions packages/cli/src/lib/platform/authenticatedClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,23 @@ export class AuthenticatedClient {
}
}
}

export enum AuthenticationStatus {
LOGGED_IN,
EXPIRED,
LOGGED_OUT,
}

export async function getAuthenticationStatus() {
const authenticatedClient = new AuthenticatedClient();

if (!(await authenticatedClient.isLoggedIn())) {
return AuthenticationStatus.LOGGED_OUT;
}

if (await authenticatedClient.isExpired()) {
return AuthenticationStatus.EXPIRED;
}

return AuthenticationStatus.LOGGED_IN;
}

0 comments on commit 1c9964e

Please sign in to comment.