mirror of https://github.com/buster-so/buster.git
remove delted at clause on user
This commit is contained in:
parent
2bc11900b9
commit
cbd8b21203
|
@ -20,7 +20,7 @@ describe('slack-authentication', () => {
|
|||
const mockIntegration = {
|
||||
id: 'int-123',
|
||||
organizationId: 'org-123',
|
||||
userId: 'user-123',
|
||||
userId: 'installer-123',
|
||||
tokenVaultKey: 'token-key',
|
||||
};
|
||||
|
||||
|
@ -40,7 +40,7 @@ describe('slack-authentication', () => {
|
|||
mockIntegration as any
|
||||
);
|
||||
vi.mocked(SlackHelpers.getAccessToken).mockResolvedValue('slack-token');
|
||||
vi.mocked(SlackHelpers.getUserById).mockResolvedValue(mockUser as any);
|
||||
vi.mocked(SlackHelpers.getUserByEmail).mockResolvedValue(mockUser as any);
|
||||
|
||||
const mockSlackUserService = {
|
||||
isBot: vi.fn().mockResolvedValue(false),
|
||||
|
@ -76,6 +76,11 @@ describe('slack-authentication', () => {
|
|||
expect(mockSlackUserService.isBot).toHaveBeenCalledWith('slack-token', 'U123456');
|
||||
expect(mockSlackUserService.isDeleted).toHaveBeenCalledWith('slack-token', 'U123456');
|
||||
expect(mockSlackUserService.getUserInfo).toHaveBeenCalledWith('slack-token', 'U123456');
|
||||
expect(vi.mocked(SlackHelpers.getUserByEmail)).toHaveBeenCalledWith('john@example.com');
|
||||
expect(vi.mocked(accessControls.checkUserInOrganization)).toHaveBeenCalledWith(
|
||||
'user-123',
|
||||
'org-123'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return unauthorized for bot users', async () => {
|
||||
|
@ -152,14 +157,21 @@ describe('slack-authentication', () => {
|
|||
const mockIntegration = {
|
||||
id: 'int-123',
|
||||
organizationId: 'org-123',
|
||||
userId: 'user-123',
|
||||
userId: 'installer-123',
|
||||
tokenVaultKey: 'token-key',
|
||||
};
|
||||
|
||||
const mockUser = {
|
||||
id: 'user-123',
|
||||
email: 'john@example.com',
|
||||
name: 'John Doe',
|
||||
};
|
||||
|
||||
vi.mocked(SlackHelpers.getActiveIntegrationByTeamId).mockResolvedValue(
|
||||
mockIntegration as any
|
||||
);
|
||||
vi.mocked(SlackHelpers.getAccessToken).mockResolvedValue('slack-token');
|
||||
vi.mocked(SlackHelpers.getUserByEmail).mockResolvedValue(mockUser as any);
|
||||
|
||||
const mockSlackUserService = {
|
||||
isBot: vi.fn().mockResolvedValue(false),
|
||||
|
@ -215,6 +227,7 @@ describe('slack-authentication', () => {
|
|||
mockIntegration as any
|
||||
);
|
||||
vi.mocked(SlackHelpers.getAccessToken).mockResolvedValue('slack-token');
|
||||
vi.mocked(SlackHelpers.getUserByEmail).mockResolvedValue(null); // No existing user
|
||||
|
||||
const mockSlackUserService = {
|
||||
isBot: vi.fn().mockResolvedValue(false),
|
||||
|
@ -230,7 +243,6 @@ describe('slack-authentication', () => {
|
|||
};
|
||||
vi.mocked(SlackUserService).mockImplementation(() => mockSlackUserService as any);
|
||||
|
||||
vi.mocked(accessControls.checkUserInOrganization).mockResolvedValue(null);
|
||||
vi.mocked(accessControls.getOrganizationWithDefaults).mockResolvedValue(mockOrg as any);
|
||||
vi.mocked(accessControls.checkEmailDomainForOrganization).mockResolvedValue(true);
|
||||
vi.mocked(accessControls.createUserInOrganization).mockResolvedValue({
|
||||
|
@ -259,6 +271,69 @@ describe('slack-authentication', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should auto-provision existing user when they are not in org but domain matches', async () => {
|
||||
const mockIntegration = {
|
||||
id: 'int-123',
|
||||
organizationId: 'org-123',
|
||||
userId: 'installer-123',
|
||||
tokenVaultKey: 'token-key',
|
||||
};
|
||||
|
||||
const mockOrg = {
|
||||
id: 'org-123',
|
||||
name: 'Example Org',
|
||||
defaultRole: 'restricted_querier',
|
||||
domains: ['example.com'],
|
||||
};
|
||||
|
||||
const mockExistingUser = {
|
||||
id: 'existing-user-123',
|
||||
email: 'existing@example.com',
|
||||
name: 'Existing User',
|
||||
};
|
||||
|
||||
vi.mocked(SlackHelpers.getActiveIntegrationByTeamId).mockResolvedValue(
|
||||
mockIntegration as any
|
||||
);
|
||||
vi.mocked(SlackHelpers.getAccessToken).mockResolvedValue('slack-token');
|
||||
vi.mocked(SlackHelpers.getUserByEmail).mockResolvedValue(mockExistingUser as any);
|
||||
|
||||
const mockSlackUserService = {
|
||||
isBot: vi.fn().mockResolvedValue(false),
|
||||
isDeleted: vi.fn().mockResolvedValue(false),
|
||||
getUserInfo: vi.fn().mockResolvedValue({
|
||||
id: 'U123456',
|
||||
real_name: 'Existing User',
|
||||
name: 'existing',
|
||||
profile: {
|
||||
email: 'existing@example.com',
|
||||
},
|
||||
}),
|
||||
};
|
||||
vi.mocked(SlackUserService).mockImplementation(() => mockSlackUserService as any);
|
||||
|
||||
vi.mocked(accessControls.checkUserInOrganization).mockResolvedValue(null); // Not in org
|
||||
vi.mocked(accessControls.getOrganizationWithDefaults).mockResolvedValue(mockOrg as any);
|
||||
vi.mocked(accessControls.checkEmailDomainForOrganization).mockResolvedValue(true);
|
||||
vi.mocked(accessControls.createUserInOrganization).mockResolvedValue({
|
||||
user: mockExistingUser as any,
|
||||
membership: {
|
||||
userId: 'existing-user-123',
|
||||
organizationId: 'org-123',
|
||||
role: 'restricted_querier',
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
|
||||
const result = await authenticateSlackUser('U123456', 'T123456');
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'auto_provisioned',
|
||||
user: mockExistingUser,
|
||||
organization: mockOrg,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return unauthorized when domain does not match', async () => {
|
||||
const mockIntegration = {
|
||||
id: 'int-123',
|
||||
|
@ -278,6 +353,7 @@ describe('slack-authentication', () => {
|
|||
mockIntegration as any
|
||||
);
|
||||
vi.mocked(SlackHelpers.getAccessToken).mockResolvedValue('slack-token');
|
||||
vi.mocked(SlackHelpers.getUserByEmail).mockResolvedValue(null); // No existing user
|
||||
|
||||
const mockSlackUserService = {
|
||||
isBot: vi.fn().mockResolvedValue(false),
|
||||
|
@ -293,7 +369,6 @@ describe('slack-authentication', () => {
|
|||
};
|
||||
vi.mocked(SlackUserService).mockImplementation(() => mockSlackUserService as any);
|
||||
|
||||
vi.mocked(accessControls.checkUserInOrganization).mockResolvedValue(null);
|
||||
vi.mocked(accessControls.getOrganizationWithDefaults).mockResolvedValue(mockOrg as any);
|
||||
vi.mocked(accessControls.checkEmailDomainForOrganization).mockResolvedValue(false);
|
||||
|
||||
|
|
|
@ -98,39 +98,42 @@ export async function authenticateSlackUser(
|
|||
};
|
||||
}
|
||||
|
||||
// Check if user exists in the organization
|
||||
const userOrgInfo = await checkUserInOrganization(
|
||||
integration.userId,
|
||||
integration.organizationId
|
||||
);
|
||||
// Check if a Buster user exists with this email
|
||||
const existingUser = await SlackHelpers.getUserByEmail(userEmail);
|
||||
|
||||
if (existingUser) {
|
||||
// User exists - check if they belong to this organization
|
||||
const userOrgInfo = await checkUserInOrganization(
|
||||
existingUser.id,
|
||||
integration.organizationId
|
||||
);
|
||||
|
||||
if (userOrgInfo) {
|
||||
// User exists in organization - check their status
|
||||
if (userOrgInfo.status !== 'active') {
|
||||
return {
|
||||
type: 'unauthorized',
|
||||
reason: `User account is ${userOrgInfo.status}. Please contact your administrator.`,
|
||||
};
|
||||
}
|
||||
|
||||
// Get organization data
|
||||
const organization = await getOrganizationWithDefaults(integration.organizationId);
|
||||
|
||||
if (!organization) {
|
||||
return {
|
||||
type: 'unauthorized',
|
||||
reason: 'Failed to load organization data',
|
||||
};
|
||||
}
|
||||
|
||||
if (userOrgInfo) {
|
||||
// User exists - check their status
|
||||
if (userOrgInfo.status !== 'active') {
|
||||
return {
|
||||
type: 'unauthorized',
|
||||
reason: `User account is ${userOrgInfo.status}. Please contact your administrator.`,
|
||||
type: 'authorized',
|
||||
user: existingUser,
|
||||
organization,
|
||||
};
|
||||
}
|
||||
|
||||
// Get full user and organization data concurrently
|
||||
const [user, organization] = await Promise.all([
|
||||
SlackHelpers.getUserById(integration.userId),
|
||||
getOrganizationWithDefaults(integration.organizationId),
|
||||
]);
|
||||
|
||||
if (!user || !organization) {
|
||||
return {
|
||||
type: 'unauthorized',
|
||||
reason: 'Failed to load user or organization data',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'authorized',
|
||||
user,
|
||||
organization,
|
||||
};
|
||||
// User exists but not in this organization - fall through to domain check
|
||||
}
|
||||
|
||||
// User doesn't exist - check if we can auto-provision
|
||||
|
|
|
@ -460,6 +460,26 @@ export async function getUserById(userId: string): Promise<User | null> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user by email address
|
||||
*/
|
||||
export async function getUserByEmail(email: string): Promise<User | null> {
|
||||
try {
|
||||
const [user] = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(and(eq(users.email, email)))
|
||||
.limit(1);
|
||||
|
||||
return user || null;
|
||||
} catch (error) {
|
||||
console.error('Failed to get user by email:', error);
|
||||
throw new Error(
|
||||
`Failed to get user by email: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Export as namespace for easier import
|
||||
export const SlackHelpers = {
|
||||
getActiveIntegration,
|
||||
|
@ -477,4 +497,5 @@ export const SlackHelpers = {
|
|||
getActiveIntegrationByTeamId,
|
||||
getAccessToken,
|
||||
getUserById,
|
||||
getUserByEmail,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue