Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tidy-invites-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperdx/api': patch
---

Apply configured default connections and sources when a user accepts a team invite.
6 changes: 6 additions & 0 deletions packages/api/src/controllers/__tests__/team.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getTeamInviteUrl,
} from '@/controllers/team';
import { clearDBCollections, closeDB, connectDB } from '@/fixtures';
import Team from '@/models/team';

describe('getTeamInviteUrl', () => {
it('builds the join-team URL for a token', () => {
Expand Down Expand Up @@ -37,7 +38,12 @@ describe('team controller', () => {

await team.save();

const otherTeam = await Team.create({ name: 'Other Team' });

expect(await getTeam(team._id)).toBeTruthy();
expect((await getTeam(otherTeam._id))?._id.toString()).toBe(
otherTeam._id.toString(),
);
expect(await getTeamByApiKey('apiKey')).toBeTruthy();
});
});
2 changes: 1 addition & 1 deletion packages/api/src/controllers/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function getTeam(id: string | ObjectId, fields?: readonly string[]) {
return LOCAL_APP_TEAM as any;
}

return Team.findOne({}, fields);
return Team.findById(id, fields);
}

export function getTeamByApiKey(apiKey: string) {
Expand Down
24 changes: 23 additions & 1 deletion packages/api/src/routers/api/__tests__/team.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import _ from 'lodash';
import { ObjectId } from 'mongodb';
import mongoose from 'mongoose';

import { getLoggedInAgent, getServer } from '@/fixtures';
import { getAgent, getLoggedInAgent, getServer } from '@/fixtures';
import Alert, { AlertSource, AlertThresholdType } from '@/models/alert';
import Team from '@/models/team';
import TeamInvite from '@/models/teamInvite';
import User from '@/models/user';
import * as setupDefaults from '@/setupDefaults';

describe('team router', () => {
const server = getServer();
Expand All @@ -16,6 +17,7 @@ describe('team router', () => {
});

afterEach(async () => {
jest.restoreAllMocks();
await server.clearDBs();
});

Expand Down Expand Up @@ -153,6 +155,26 @@ describe('team router', () => {
expect(resp.body.url).toContain(`/join-team?token=${teamInvite.token}`);
});

it('POST /team/setup/:token provisions defaults for the invited team', async () => {
const { team } = await getLoggedInAgent(server);
const invite = await TeamInvite.create({
email: 'invited@example.com',
name: 'Invited User',
teamId: team._id,
token: 'invite_token',
});
const setupTeamDefaults = jest
.spyOn(setupDefaults, 'setupTeamDefaults')
.mockResolvedValue();

await getAgent(server)
.post(`/team/setup/${invite.token}`)
.send({ password: 'TacoCat!2#4X' })
.expect(303);

expect(setupTeamDefaults).toHaveBeenCalledWith(team._id.toString());
});

it('POST /team/invitation with different case reuses existing invitation', async () => {
const { agent } = await getLoggedInAgent(server);

Expand Down
22 changes: 22 additions & 0 deletions packages/api/src/routers/api/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { handleAuthError, redirectToDashboard } from '@/middleware/auth';
import TeamInvite from '@/models/teamInvite';
import User from '@/models/user'; // TODO -> do not import model directly
import { setupTeamDefaults } from '@/setupDefaults';
import {
setBusinessContext,
withOperationMetrics,
} from '@/utils/instrumentation';
import logger from '@/utils/logger';
import passport from '@/utils/passport';
import { isMongoConnected, mongoReadyStateName } from '@/utils/readiness';
Expand Down Expand Up @@ -188,6 +192,24 @@ router.post('/team/setup/:token', async (req, res, next) => {
);
}

const teamId = teamInvite.teamId.toString();
setBusinessContext({
teamId,
userId: user._id.toString(),
email: user.email,
});

try {
await withOperationMetrics('team_defaults.setup', () =>
setupTeamDefaults(teamId),
);
} catch (error) {
logger.error(
{ err: serializeError(error) },
'Failed to setup team defaults',
);
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Resolved
}

await TeamInvite.findByIdAndRemove(teamInvite._id);

req.login(user, err => {
Expand Down