Skip to content

Commit

Permalink
Merge pull request #128 from vtex-apps/feature/B2BTEAM-1255-buyer-org…
Browse files Browse the repository at this point in the history
…-users-metrics

feat: buyer org users metrics
  • Loading branch information
Rudge authored Sep 25, 2023
2 parents e5e5da7 + d918656 commit 9f0d826
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 58 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- Add metrics to maintain buyer organization users

## [0.38.0] - 2023-09-25

### Added
Expand Down
65 changes: 41 additions & 24 deletions node/resolvers/Mutations/Users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import {
sendImpersonateB2BUserMetric,
sendImpersonateUserMetric,
} from '../../utils/metrics/impersonate'
import {
sendAddUserMetric,
sendRemoveUserMetric,
sendUpdateUserMetric,
} from '../../utils/metrics/user'

export const getUserRoleSlug: (
id: string,
Expand Down Expand Up @@ -406,18 +411,22 @@ const Users = {
}
}

const fields = {
email,
id,
userId,
}

return storefrontPermissionsClient
.deleteUser({
email,
id,
userId,
})
.deleteUser(fields)
.then((result: any) => {
events.sendEvent('', 'b2b-organizations-graphql.removeUser', {
id,
email,
})

sendRemoveUserMetric(logger, ctx.vtex.account, fields)

return result.data.deleteUser
})
.catch((error: any) => {
Expand Down Expand Up @@ -460,17 +469,21 @@ const Users = {
throw error
}

const fields = {
costId,
email,
id,
name,
orgId,
roleId,
userId,
}

return storefrontPermissionsClient
.addUser({
costId,
email,
id,
name,
orgId,
roleId,
userId,
})
.addUser(fields)
.then((result: any) => {
sendAddUserMetric(logger, ctx.vtex.account, fields)

return result.data.addUser
})
.catch((error: any) => {
Expand Down Expand Up @@ -538,18 +551,22 @@ const Users = {
})
}

const fields = {
clId,
costId,
email,
id,
name,
orgId,
roleId,
userId,
}

return storefrontPermissionsClient
.updateUser({
clId,
costId,
email,
id,
name,
orgId,
roleId,
userId,
})
.updateUser(fields)
.then((result: any) => {
sendUpdateUserMetric(logger, ctx.vtex.account, fields)

return result.data.updateUser
})
.catch((error: any) => {
Expand Down
33 changes: 6 additions & 27 deletions node/utils/metrics/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,13 @@ import axios from 'axios'

const ANALYTICS_URL = 'https://rc.vtex.com/api/analytics/schemaless-events'

type ImpersonateUserMetric = {
kind: 'impersonate-user-graphql-event'
description: 'Impersonate User Action - Graphql'
export interface Metric {
readonly account: string
readonly kind: string
readonly description: string
readonly name: 'b2b-suite-buyerorg-data'
}

type ImpersonateB2BUserMetric = {
kind: 'impersonate-b2b-user-graphql-event'
description: 'Impersonate B2B User Action - Graphql'
}

interface UpdateOrganizationMetric {
kind: 'update-organization-graphql-event'
description: 'Update Organization Action - Graphql'
}

export type Metric = {
name: 'b2b-suite-buyerorg-data'
account: string
} & (
| ImpersonateUserMetric
| ImpersonateB2BUserMetric
| UpdateOrganizationMetric
)

export const sendMetric = async (metric: Metric) => {
try {
await axios.post(ANALYTICS_URL, metric)
} catch (error) {
console.warn('Unable to log metrics', error)
}
await axios.post(ANALYTICS_URL, metric)
}
21 changes: 14 additions & 7 deletions node/utils/metrics/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ export interface UpdateOrganizationParams {
updatedProperties: Partial<Organization>
}

class UpdateOrganizationMetric implements Metric {
public readonly description = 'Update Organization Action - Graphql'
public readonly kind = 'update-organization-graphql-event'
public readonly account: string
public readonly fields: UpdateOrganizationFieldsMetric
public readonly name = 'b2b-suite-buyerorg-data'

constructor(account: string, fields: UpdateOrganizationFieldsMetric) {
this.account = account
this.fields = fields
}
}

const buildUpdateOrganizationMetric = (
account: string,
updatedProperties: string[]
Expand All @@ -26,13 +39,7 @@ const buildUpdateOrganizationMetric = (
update_details: { properties: updatedProperties },
}

return {
account,
description: 'Update Organization Action - Graphql',
fields: updateOrganizationFields,
kind: 'update-organization-graphql-event',
name: 'b2b-suite-buyerorg-data',
} as UpdateOrganization
return new UpdateOrganizationMetric(account, updateOrganizationFields)
}

const getPropNamesByUpdateParams = (
Expand Down
100 changes: 100 additions & 0 deletions node/utils/metrics/user.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { randEmail, randWord } from '@ngneat/falso'
import type { Logger } from '@vtex/api/lib/service/logger/logger'

import { sendMetric } from './metrics'
import {
sendAddUserMetric,
sendRemoveUserMetric,
sendUpdateUserMetric,
} from './user'

jest.mock('./metrics')
afterEach(() => {
jest.resetAllMocks()
})

describe('given an action for a user', () => {
describe('when add user', () => {
const logger = jest.fn() as unknown as Logger

const account = randWord()

const userArgs: Partial<UserArgs> = {
email: randEmail(),
id: randWord(),
userId: randWord(),
}

beforeEach(async () => {
await sendAddUserMetric(logger, account, userArgs)
})

it('should metrify the action', () => {
const metricParam = {
account,
description: 'Add User Action - Graphql',
fields: userArgs,
kind: 'add-user-graphql-event',
name: 'b2b-suite-buyerorg-data',
}

expect(sendMetric).toHaveBeenCalledWith(metricParam)
})
})

describe('when remove user', () => {
const logger = jest.fn() as unknown as Logger

const account = randWord()

const userArgs: Partial<UserArgs> = {
email: randEmail(),
id: randWord(),
userId: randWord(),
}

beforeEach(async () => {
await sendRemoveUserMetric(logger, account, userArgs)
})

it('should metrify the action', () => {
const metricParam = {
account,
description: 'Remove User Action - Graphql',
fields: userArgs,
kind: 'remove-user-graphql-event',
name: 'b2b-suite-buyerorg-data',
}

expect(sendMetric).toHaveBeenCalledWith(metricParam)
})
})

describe('when update user', () => {
const logger = jest.fn() as unknown as Logger

const account = randWord()

const userArgs: Partial<UserArgs> = {
email: randEmail(),
id: randWord(),
userId: randWord(),
}

beforeEach(async () => {
await sendUpdateUserMetric(logger, account, userArgs)
})

it('should metrify the action', () => {
const metricParam = {
account,
description: 'Update User Action - Graphql',
fields: userArgs,
kind: 'update-user-graphql-event',
name: 'b2b-suite-buyerorg-data',
}

expect(sendMetric).toHaveBeenCalledWith(metricParam)
})
})
})
87 changes: 87 additions & 0 deletions node/utils/metrics/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type { Logger } from '@vtex/api/lib/service/logger/logger'

import type { Metric } from './metrics'
import { sendMetric } from './metrics'

interface UserMetricType {
description: string
kind: string
}

const userMetricType = {
add: {
description: 'Add User Action - Graphql',
kind: 'add-user-graphql-event',
} as UserMetricType,
remove: {
description: 'Remove User Action - Graphql',
kind: 'remove-user-graphql-event',
} as UserMetricType,
update: {
description: 'Update User Action - Graphql',
kind: 'update-user-graphql-event',
} as UserMetricType,
}

class UserMetric implements Metric {
public readonly description: string
public readonly kind: string
public readonly account: string
public readonly fields: Partial<UserArgs>
public readonly name = 'b2b-suite-buyerorg-data'

constructor(
account: string,
{ kind, description }: UserMetricType,
fields: Partial<UserArgs>
) {
this.account = account
this.fields = fields
this.kind = kind
this.description = description
}
}

const sendUserMetric = async (logger: Logger, userMetric: UserMetric) => {
try {
await sendMetric(userMetric)
} catch (error) {
logger.error({
error,
message: `Error to send metrics from user action ${userMetric.kind}`,
})
}
}

export const sendRemoveUserMetric = async (
logger: Logger,
account: string,
userArgs: Partial<UserArgs>
) => {
await sendUserMetric(
logger,
new UserMetric(account, userMetricType.remove, userArgs)
)
}

export const sendAddUserMetric = async (
logger: Logger,
account: string,
userArgs: Partial<UserArgs>
) => {
await sendUserMetric(
logger,
new UserMetric(account, userMetricType.add, userArgs)
)
}

export const sendUpdateUserMetric = async (
logger: Logger,
account: string,
userArgs: Partial<UserArgs>
) => {
await sendUserMetric(
logger,
new UserMetric(account, userMetricType.update, userArgs)
)
}
1 change: 1 addition & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
sonar.projectKey=vtex-apps_b2b-organizations-graphql
sonar.organization=vtex-apps
sonar.coverage.exclusions=**/*.test.*, */__mocks__/**.*, */node_modules/**.*, node/index.ts
sonar.exclusions=**/*.test.*, */__mocks__/**.*, */node_modules/**.*, node/index.ts
sonar.language=ts
sonar.javascript.lcov.reportPaths=./node/coverage/lcov.info

0 comments on commit 9f0d826

Please sign in to comment.