diff --git a/src/client/components/feed/FeedIntegration.tsx b/src/client/components/feed/FeedIntegration.tsx
index 6d474da..00524f3 100644
--- a/src/client/components/feed/FeedIntegration.tsx
+++ b/src/client/components/feed/FeedIntegration.tsx
@@ -3,6 +3,7 @@ import { LuGithub, LuPlug } from 'react-icons/lu';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import { CodeBlock } from '../CodeBlock';
import { useTranslation } from '@i18next-toolkit/react';
+import { SiSentry } from 'react-icons/si';
export const FeedIntegration: React.FC<{
feedId: string;
@@ -29,6 +30,22 @@ export const FeedIntegration: React.FC<{
}
/>
+ }
+ label="Sentry"
+ content={
+
+
{t('Receive Webhooks')}
+
+
{t('Add sentry webhook with url')}:
+
+
+
+ }
+ />
+
}
label="Custom"
diff --git a/src/server/app.ts b/src/server/app.ts
index 8e84f88..39b54a2 100644
--- a/src/server/app.ts
+++ b/src/server/app.ts
@@ -27,7 +27,11 @@ const app = express();
app.set('trust proxy', true);
app.use(compression());
-app.use(express.json());
+app.use(
+ express.json({
+ limit: '10mb',
+ })
+);
app.use(passport.initialize());
app.use(morgan('tiny'));
app.use(cors());
diff --git a/src/server/trpc/routers/feed/integration.ts b/src/server/trpc/routers/feed/integration.ts
index d2ff68a..3df0f1d 100644
--- a/src/server/trpc/routers/feed/integration.ts
+++ b/src/server/trpc/routers/feed/integration.ts
@@ -6,7 +6,7 @@ import { OPENAPI_TAG } from '../../../utils/const.js';
import { createFeedEvent } from '../../../model/feed/event.js';
import { tencentCloudAlarmSchema } from '../../../model/_schema/feed.js';
import { logger } from '../../../utils/logger.js';
-import { get, map } from 'lodash-es';
+import { compact, fromPairs, get, map } from 'lodash-es';
export const feedIntegrationRouter = router({
github: publicProcedure
@@ -109,7 +109,6 @@ export const feedIntegrationRouter = router({
return 'ok';
} else if (eventType === 'issues') {
const action = get(data, 'action') as 'opened' | 'closed';
- const starCount = get(data, 'repository.stargazers_count');
const fullName = get(data, 'repository.full_name');
const repoUrl = get(data, 'repository.html_url');
const senderId = String(get(data, 'sender.id'));
@@ -234,6 +233,73 @@ export const feedIntegrationRouter = router({
return 'ok';
}
+ return 'Not supported yet';
+ }),
+ sentry: publicProcedure
+ .meta(
+ buildFeedPublicOpenapi({
+ method: 'POST',
+ path: '/{channelId}/sentry',
+ summary: 'integrate with sentry webhook',
+ })
+ )
+ .input(
+ z
+ .object({
+ channelId: z.string(),
+ })
+ .passthrough()
+ )
+ .output(z.string())
+ .mutation(async ({ input, ctx }) => {
+ const { channelId, ...data } = input;
+ const eventType = ctx.req.headers['sentry-hook-resource'];
+
+ const workspaceId = await prisma.feedChannel
+ .findFirst({
+ where: {
+ id: channelId,
+ },
+ select: {
+ workspaceId: true,
+ },
+ })
+ .then((res) => res?.workspaceId);
+
+ if (!workspaceId) {
+ throw new Error('Not found Workspace');
+ }
+
+ const action = get(data, 'action');
+
+ if (eventType === 'event_alert' && action === 'triggered') {
+ const message = get(data, 'data.event.message');
+ const tags = fromPairs(get(data as any, 'data.event.tags'));
+ const url = String(get(data, 'data.event.web_url'));
+ const senderId = String(get(data, 'data.actor.id'));
+ const senderName = String(get(data, 'data.actor.name'));
+
+ await createFeedEvent(workspaceId, {
+ channelId: channelId,
+ eventName: 'alert',
+ eventContent: `${message}`,
+ tags: compact([
+ tags['environment'],
+ tags['release'],
+ tags['browser'],
+ tags['os'],
+ tags['device'],
+ ]),
+ source: 'sentry',
+ senderId,
+ senderName,
+ important: false,
+ url,
+ });
+
+ return 'ok';
+ }
+
return 'Not supported yet';
}),
});