From e610fe733530c63c1b58670c32d03c4056f71682 Mon Sep 17 00:00:00 2001 From: javayhu Date: Sat, 14 Jun 2025 02:09:40 +0800 Subject: [PATCH] feat: support send message to feishu --- env.example | 6 +++ src/{lib => notification}/discord.ts | 1 - src/notification/feishu.ts | 55 ++++++++++++++++++++++++++++ src/notification/notification.ts | 24 ++++++++++++ src/payment/provider/stripe.ts | 6 +-- 5 files changed, 88 insertions(+), 4 deletions(-) rename src/{lib => notification}/discord.ts (96%) create mode 100644 src/notification/feishu.ts create mode 100644 src/notification/notification.ts diff --git a/env.example b/env.example index 29488a6..b4c8c4c 100644 --- a/env.example +++ b/env.example @@ -127,9 +127,15 @@ NEXT_PUBLIC_DATAFAST_ANALYTICS_DOMAIN="" # ----------------------------------------------------------------------------- # Discord # ----------------------------------------------------------------------------- +DISCORD_WEBHOOK_URL="" NEXT_PUBLIC_DISCORD_WIDGET_SERVER_ID="" NEXT_PUBLIC_DISCORD_WIDGET_CHANNEL_ID="" +# ----------------------------------------------------------------------------- +# Feishu +# ----------------------------------------------------------------------------- +FEISHU_WEBHOOK_URL="" + # ----------------------------------------------------------------------------- # Affiliate # https://mksaas.com/docs/affiliate diff --git a/src/lib/discord.ts b/src/notification/discord.ts similarity index 96% rename from src/lib/discord.ts rename to src/notification/discord.ts index a25d744..005e216 100644 --- a/src/lib/discord.ts +++ b/src/notification/discord.ts @@ -67,7 +67,6 @@ export async function sendMessageToDiscord( }); if (!response.ok) { - // throw new Error(`Discord webhook request failed with status ${response.status}`); console.error( `<< Failed to send Discord notification for user ${userName}:`, response diff --git a/src/notification/feishu.ts b/src/notification/feishu.ts new file mode 100644 index 0000000..d2ec7c4 --- /dev/null +++ b/src/notification/feishu.ts @@ -0,0 +1,55 @@ +/** + * Send a message to Feishu when a user makes a purchase + * @param sessionId The Stripe checkout session ID + * @param customerId The Stripe customer ID + * @param userName The username of the customer + * @param amount The purchase amount in the currency's main unit (e.g., dollars, not cents) + */ +export async function sendMessageToFeishu( + sessionId: string, + customerId: string, + userName: string, + amount: number +): Promise { + try { + const webhookUrl = process.env.FEISHU_WEBHOOK_URL; + + if (!webhookUrl) { + console.warn( + 'FEISHU_WEBHOOK_URL is not set, skipping Feishu notification' + ); + return; + } + + // Format the message + const message = { + msg_type: 'text', + content: { + text: `🎉 New Purchase\nUsername: ${userName}\nAmount: $${amount.toFixed(2)}\nCustomer ID: \`${customerId}\`\nSession ID: \`${sessionId}\``, + }, + }; + + // Send the webhook request + const response = await fetch(webhookUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(message), + }); + + if (!response.ok) { + console.error( + `<< Failed to send Feishu notification for user ${userName}:`, + response + ); + } + + console.log( + `<< Successfully sent Feishu notification for user ${userName}` + ); + } catch (error) { + console.error('<< Failed to send Feishu notification:', error); + // Don't rethrow the error to avoid interrupting the payment flow + } +} diff --git a/src/notification/notification.ts b/src/notification/notification.ts new file mode 100644 index 0000000..18c426d --- /dev/null +++ b/src/notification/notification.ts @@ -0,0 +1,24 @@ +import { sendMessageToDiscord } from './discord'; +import { sendMessageToFeishu } from './feishu'; + +/** + * Send a notification when a user makes a purchase + * @param sessionId The Stripe checkout session ID + * @param customerId The Stripe customer ID + * @param userName The username of the customer + * @param amount The purchase amount in the currency's main unit (e.g., dollars, not cents) + */ +export async function sendNotification( + sessionId: string, + customerId: string, + userName: string, + amount: number +): Promise { + console.log('sendNotification', sessionId, customerId, userName, amount); + + // Send message to Discord channel + await sendMessageToDiscord(sessionId, customerId, userName, amount); + + // Send message to Feishu group + await sendMessageToFeishu(sessionId, customerId, userName, amount); +} diff --git a/src/payment/provider/stripe.ts b/src/payment/provider/stripe.ts index 5800534..92c976f 100644 --- a/src/payment/provider/stripe.ts +++ b/src/payment/provider/stripe.ts @@ -1,12 +1,12 @@ import { randomUUID } from 'crypto'; import { getDb } from '@/db'; import { payment, session, user } from '@/db/schema'; -import { sendMessageToDiscord } from '@/lib/discord'; import { findPlanByPlanId, findPlanByPriceId, findPriceInPlan, } from '@/lib/price-plan'; +import { sendNotification } from '@/notification/notification'; import { desc, eq } from 'drizzle-orm'; import { Stripe } from 'stripe'; import { @@ -626,9 +626,9 @@ export class StripeProvider implements PaymentProvider { `<< Created one-time payment record for user ${userId}, price: ${priceId}` ); - // Send message to Discord channel + // Send notification const amount = session.amount_total ? session.amount_total / 100 : 0; - await sendMessageToDiscord(session.id, customerId, userId, amount); + await sendNotification(session.id, customerId, userId, amount); } /**