Skip to content

Commit

Permalink
feat-added slack integration and unit test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
adityaRajGit committed Nov 10, 2024
1 parent 7c8ee5d commit 19777e4
Show file tree
Hide file tree
Showing 14 changed files with 3,184 additions and 243 deletions.
2,450 changes: 2,361 additions & 89 deletions apps/api/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
"@nestjs/swagger": "^7.3.0",
"@nestjs/throttler": "^6.2.1",
"@nestjs/websockets": "^10.3.7",
"@slack/bolt": "^3.13.1",
"@socket.io/redis-adapter": "^8.3.0",
"@supabase/supabase-js": "^2.39.6",
"api": "file:",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie-parser": "^1.4.6",
Expand Down
6 changes: 6 additions & 0 deletions apps/api/src/integration/integration.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ export interface DiscordIntegrationMetadata extends IntegrationMetadata {
webhookUrl: string
}

export interface SlackIntegrationMetadata extends IntegrationMetadata {
botToken: string;
signingSecret: string;
channelId: string;
}

export interface IntegrationWithWorkspace extends Integration {
workspace: Workspace
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IntegrationType } from '@prisma/client'
import { BaseIntegration } from '../base.integration'
import { DiscordIntegration } from '../discord/discord.integration'
import { InternalServerErrorException } from '@nestjs/common'
import { SlackIntegration } from '../slack/slack.integration'

/**
* Factory class to create integrations. This class will be called to create an integration,
Expand All @@ -20,6 +21,8 @@ export default class IntegrationFactory {
switch (integrationType) {
case IntegrationType.DISCORD:
return new DiscordIntegration()
case IntegrationType.SLACK:
return new SlackIntegration()
default:
throw new InternalServerErrorException('Integration type not found')
}
Expand Down
30 changes: 30 additions & 0 deletions apps/api/src/integration/plugins/slack/slack.integration.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { IntegrationType } from '@prisma/client'
import { SlackIntegration } from './slack.integration'

describe('Slack Integration Test', () => {
let integration: SlackIntegration

beforeEach(() => {
integration = new SlackIntegration()
})

it('should generate slack integration', () => {
expect(integration).toBeDefined()
expect(integration.integrationType).toBe(IntegrationType.SLACK)
})

it('should have the correct permitted events', () => {
const events = integration.getPermittedEvents()
expect(events).toBeDefined()
expect(events.size).toBe(26)
})

it('should have the correct required metadata parameters', () => {
const metadata = integration.getRequiredMetadataParameters()
expect(metadata).toBeDefined()
expect(metadata.size).toBe(3)
expect(metadata.has('botToken')).toBe(true)
expect(metadata.has('signingSecret')).toBe(true)
expect(metadata.has('channelId')).toBe(true)
})
})
125 changes: 125 additions & 0 deletions apps/api/src/integration/plugins/slack/slack.integration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {EventType, IntegrationType} from '@prisma/client'
import {SlackIntegrationMetadata,IntegrationEventData} from '../../integration.types'
import {App} from '@slack/bolt'
import { BaseIntegration } from '../base.integration'
import { Logger } from '@nestjs/common'
import { set, string } from 'zod'
import { MetadataScanner } from '@nestjs/core'

export class SlackIntegration extends BaseIntegration {
private readonly logger = new Logger('SlackIntegration')
private app : App;
constructor() {
super(IntegrationType.SLACK);
}


public getPermittedEvents(): Set<EventType> {
return new Set([
EventType.INTEGRATION_ADDED,
EventType.INTEGRATION_UPDATED,
EventType.INTEGRATION_DELETED,
EventType.INVITED_TO_WORKSPACE,
EventType.REMOVED_FROM_WORKSPACE,
EventType.ACCEPTED_INVITATION,
EventType.DECLINED_INVITATION,
EventType.CANCELLED_INVITATION,
EventType.LEFT_WORKSPACE,
EventType.WORKSPACE_UPDATED,
EventType.WORKSPACE_CREATED,
EventType.WORKSPACE_ROLE_CREATED,
EventType.WORKSPACE_ROLE_UPDATED,
EventType.WORKSPACE_ROLE_DELETED,
EventType.PROJECT_CREATED,
EventType.PROJECT_UPDATED,
EventType.PROJECT_DELETED,
EventType.SECRET_UPDATED,
EventType.SECRET_DELETED,
EventType.SECRET_ADDED,
EventType.VARIABLE_UPDATED,
EventType.VARIABLE_DELETED,
EventType.VARIABLE_ADDED,
EventType.ENVIRONMENT_UPDATED,
EventType.ENVIRONMENT_DELETED,
EventType.ENVIRONMENT_ADDED,
EventType.INTEGRATION_ADDED,
EventType.INTEGRATION_UPDATED,
EventType.INTEGRATION_DELETED
])
}

public getRequiredMetadataParameters(): Set<string> {
return new Set(['botToken','signingSecret','channelId'])
}

async emitEvent(
data: IntegrationEventData,
metadata: SlackIntegrationMetadata
) : Promise<void> {
this.logger.log(`Emitting event to Slack: ${data.title}`)
try{
if(!this.app)
{
this.app = new App({
token: metadata.botToken,
signingSecret: metadata.signingSecret
})
}
const block = [
{
type: 'header',
text: {
type: 'plain_text',
text: 'Update occurred on keyshade',
emoji: true
}
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*${data.title ?? 'No title provided'}*\n${data.description ?? 'No description provided'}`
}
},
{
type: 'divider'
},
{
type: 'section',
fields: [
{
type: 'mrkdwn',
text: `*Event:*\n${data.title}`
},
{
type: 'mrkdwn',
text: `*Source:*\n${data.source}`
}
]
},
{
type: 'context',
elements: [
{
type: 'mrkdwn',
text: '<https://keyshade.xyz|View in Keyshade>'
}
]
}
];
await this.app.client.chat.postMessage({
channel: metadata.channelId,
blocks: block,
text:data.title
});
}
catch(error){
this.logger.error(`Failed to emit event to Slack: ${error.message}`);
console.error(error);
throw error;
}
}
}



7 changes: 7 additions & 0 deletions packages/eslint-config-custom/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions packages/eslint-config-custom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
"version": "0.0.0",
"private": true,
"devDependencies": {
"@vercel/style-guide": "^5.0.0",
"eslint-config-turbo": "^1.10.12",
"typescript": "^4.5.3"
"@vercel/style-guide": "^5.0.0",
"eslint-config-turbo": "^1.10.12",
"typescript": "^4.5.3"
},
"dependencies": {
"eslint-config-custom": "file:"
}
}
}
19 changes: 18 additions & 1 deletion packages/schema/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"test": "jest"
},
"dependencies": {
"@keyshade/schema": "file:",
"zod": "^3.23.6"
}
}
1 change: 1 addition & 0 deletions packages/secret-scan/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
".": "./dist/index.js"
},
"dependencies": {
"@keyshade/secret-scan": "file:",
"mocha": "^10.6.0",
"randexp": "^0.5.3",
"tsx": "^4.16.2"
Expand Down
9 changes: 8 additions & 1 deletion packages/tsconfig/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions packages/tsconfig/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"private": true,
"license": "MIT",
"publishConfig": {
"access": "public"
"access": "public"
},
"dependencies": {
"tsconfig": "file:"
}
}
}
Loading

0 comments on commit 19777e4

Please sign in to comment.