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'; }), });