Skip to content

Commit 3a4631f

Browse files
Merge pull request #2200 from bluewave-labs/rb-sept-15-slack-integration
Rb sept 15 slack integration
2 parents f1e3a30 + 41a1747 commit 3a4631f

21 files changed

Lines changed: 2666 additions & 26 deletions

File tree

.env.dev

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ REFRESH_TOKEN_SECRET=e628d7938c76308774cecf87dcb9bee6b8cae80ed2d20731ef94e211cf9
2929
EMAIL_ID=your-email@gmail.com
3030
# Your password from: https://myaccount.google.com/apppasswords
3131
EMAIL_PASSWORD="aaaa bbbb cccc dddd"
32+
33+
# Encryption Settings
34+
ENCRYPTION_ALGORITHM=YOUR_ENCRYPTION_ALGORITHM
35+
ENCRYPTION_PASSWORD=YOUR_ENCRYPTION_PASSWORD

.env.prod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ REFRESH_TOKEN_SECRET=e628d7938c76308774cecf87dcb9bee6b8cae80ed2d20731ef94e211cf9
3131
EMAIL_ID=your-email@gmail.com
3232
# Your password from: https://myaccount.google.com/apppasswords
3333
EMAIL_PASSWORD="aaaa bbbb cccc dddd"
34+
35+
# Encryption Settings
36+
ENCRYPTION_ALGORITHM=YOUR_ENCRYPTION_ALGORITHM
37+
ENCRYPTION_PASSWORD=YOUR_ENCRYPTION_PASSWORD

Clients/env.vars.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ export const ENV_VARs = {
88
: "http://localhost:3000/"), // final Node/SSR fallback
99
IS_DEMO_APP: import.meta.env.VITE_IS_DEMO_APP === "true",
1010
IS_MULTI_TENANT: import.meta.env.VITE_IS_MULTI_TENANT === "true",
11+
CLIENT_ID: import.meta.env.VITE_CLIENT_ID,
12+
SLACK_URL: import.meta.env.VITE_SLACK_URL,
1113
};

Clients/src/application/constants/permissions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ const allowedRoles = {
4141
edit: ["Admin", "Editor"],
4242
delete: ["Admin", "Editor"],
4343
},
44+
slack: {
45+
view: ["Admin"],
46+
manage: ["Admin"],
47+
},
4448
};
4549

4650
export default allowedRoles;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { useEffect, useState } from "react";
2+
import { getSlackIntegrations } from "../repository/slack.integration.repository";
3+
4+
interface ISlackWebhook {
5+
id?: number;
6+
access_token_iv?: string;
7+
access_token: string;
8+
scope: string;
9+
user_id?: number; // FK to users table
10+
team_name: string;
11+
team_id: string;
12+
channel: string;
13+
channel_id: string;
14+
configuration_url: string; // configuration URL to manage the webhook
15+
url_iv?: string;
16+
url: string; // URL of the slack workspace
17+
created_at?: string;
18+
is_active?: boolean;
19+
}
20+
export interface SlackWebhook {
21+
id?: number;
22+
scope: string;
23+
teamName: string;
24+
teamId: string;
25+
channel: string;
26+
channelId: string;
27+
createdAt?: string;
28+
isActive?: boolean;
29+
}
30+
31+
interface ApiResponse {
32+
data: ISlackWebhook[];
33+
}
34+
35+
const useSlackIntegrations = (userId: number | null) => {
36+
const [slackIntegrations, setSlackIntegrations] = useState<SlackWebhook[]>(
37+
[],
38+
);
39+
const [loading, setLoading] = useState(true);
40+
const [error, setError] = useState<string | null>(null);
41+
42+
const fetchSlackIntegrations = async () => {
43+
try {
44+
const controller = new AbortController();
45+
const signal = controller.signal;
46+
setLoading(true);
47+
const response = await getSlackIntegrations({ id: userId!, signal });
48+
49+
const integrations: SlackWebhook[] = (response as ApiResponse).data.map(
50+
(item: ISlackWebhook): SlackWebhook => ({
51+
id: item.id,
52+
scope: item.scope,
53+
teamName: item.team_name,
54+
teamId: item.team_id,
55+
channel: item.channel,
56+
channelId: item.channel_id,
57+
createdAt: item.created_at,
58+
isActive: item.is_active,
59+
}),
60+
);
61+
62+
setSlackIntegrations(integrations);
63+
setError(null);
64+
} catch (err) {
65+
setError(
66+
err instanceof Error
67+
? err.message
68+
: "Failed to fetch slack integrations",
69+
);
70+
} finally {
71+
setLoading(false);
72+
}
73+
};
74+
75+
useEffect(() => {
76+
fetchSlackIntegrations();
77+
}, []);
78+
79+
return {
80+
slackIntegrations,
81+
loading,
82+
error,
83+
refreshSlackIntegrations: fetchSlackIntegrations,
84+
};
85+
};
86+
87+
export default useSlackIntegrations;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { apiServices } from "../../infrastructure/api/networkServices";
2+
3+
export async function getSlackIntegrations({
4+
id,
5+
channel,
6+
signal,
7+
responseType = "json",
8+
}: {
9+
id: number;
10+
channel?: string;
11+
signal?: AbortSignal;
12+
responseType?: string;
13+
}): Promise<any> {
14+
const response = await apiServices.get(`/slackWebhooks`, {
15+
userId: id,
16+
channel,
17+
signal,
18+
responseType,
19+
});
20+
return response.data;
21+
}
22+
23+
export async function getSlackIntegrationById({
24+
id,
25+
signal,
26+
responseType = "json",
27+
}: {
28+
id: string;
29+
signal?: AbortSignal;
30+
responseType?: string;
31+
}): Promise<any> {
32+
const response = await apiServices.get(`/slackWebhooks/${id}`, {
33+
signal,
34+
responseType,
35+
});
36+
return response.data;
37+
}
38+
39+
export async function createSlackIntegration({
40+
body,
41+
}: {
42+
body: any;
43+
}): Promise<any> {
44+
const response = await apiServices.post("/slackWebhooks", body);
45+
return response.data;
46+
}
47+
48+
export async function updateSlackIntegration({
49+
id,
50+
body,
51+
}: {
52+
id: string;
53+
body: any;
54+
}): Promise<any> {
55+
const response = await apiServices.patch(`/slackWebhooks/${id}`, body);
56+
return response;
57+
}
58+
59+
export async function sendSlackMessage({
60+
id,
61+
body,
62+
}: {
63+
id: number;
64+
body: { title: string; message: string };
65+
}): Promise<any> {
66+
const response = await apiServices.post(`/slackWebhooks/${id}/send`, body);
67+
return response.data;
68+
}

0 commit comments

Comments
 (0)