Frank hai 3 semanas
pai
achega
be9a0bfee7

+ 14 - 1
infra/app.ts

@@ -4,6 +4,10 @@ const GITHUB_APP_ID = new sst.Secret("GITHUB_APP_ID")
 const GITHUB_APP_PRIVATE_KEY = new sst.Secret("GITHUB_APP_PRIVATE_KEY")
 export const EMAILOCTOPUS_API_KEY = new sst.Secret("EMAILOCTOPUS_API_KEY")
 const ADMIN_SECRET = new sst.Secret("ADMIN_SECRET")
+const DISCORD_SUPPORT_BOT_TOKEN = new sst.Secret("DISCORD_SUPPORT_BOT_TOKEN")
+const DISCORD_SUPPORT_CHANNEL_ID = new sst.Secret("DISCORD_SUPPORT_CHANNEL_ID")
+const FEISHU_APP_ID = new sst.Secret("FEISHU_APP_ID")
+const FEISHU_APP_SECRET = new sst.Secret("FEISHU_APP_SECRET")
 const bucket = new sst.cloudflare.Bucket("Bucket")
 
 export const api = new sst.cloudflare.Worker("Api", {
@@ -13,7 +17,16 @@ export const api = new sst.cloudflare.Worker("Api", {
     WEB_DOMAIN: domain,
   },
   url: true,
-  link: [bucket, GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, ADMIN_SECRET],
+  link: [
+    bucket,
+    GITHUB_APP_ID,
+    GITHUB_APP_PRIVATE_KEY,
+    ADMIN_SECRET,
+    DISCORD_SUPPORT_BOT_TOKEN,
+    DISCORD_SUPPORT_CHANNEL_ID,
+    FEISHU_APP_ID,
+    FEISHU_APP_SECRET,
+  ],
   transform: {
     worker: (args) => {
       args.logpush = true

+ 16 - 0
packages/console/core/sst-env.d.ts

@@ -34,6 +34,14 @@ declare module "sst" {
       "type": "sst.cloudflare.SolidStart"
       "url": string
     }
+    "DISCORD_SUPPORT_BOT_TOKEN": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "DISCORD_SUPPORT_CHANNEL_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "Database": {
       "database": string
       "host": string
@@ -46,6 +54,14 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "value": string
     }
+    "FEISHU_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "FEISHU_APP_SECRET": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "GITHUB_APP_ID": {
       "type": "sst.sst.Secret"
       "value": string

+ 16 - 0
packages/console/function/sst-env.d.ts

@@ -34,6 +34,14 @@ declare module "sst" {
       "type": "sst.cloudflare.SolidStart"
       "url": string
     }
+    "DISCORD_SUPPORT_BOT_TOKEN": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "DISCORD_SUPPORT_CHANNEL_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "Database": {
       "database": string
       "host": string
@@ -46,6 +54,14 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "value": string
     }
+    "FEISHU_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "FEISHU_APP_SECRET": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "GITHUB_APP_ID": {
       "type": "sst.sst.Secret"
       "value": string

+ 16 - 0
packages/console/resource/sst-env.d.ts

@@ -34,6 +34,14 @@ declare module "sst" {
       "type": "sst.cloudflare.SolidStart"
       "url": string
     }
+    "DISCORD_SUPPORT_BOT_TOKEN": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "DISCORD_SUPPORT_CHANNEL_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "Database": {
       "database": string
       "host": string
@@ -46,6 +54,14 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "value": string
     }
+    "FEISHU_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "FEISHU_APP_SECRET": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "GITHUB_APP_ID": {
       "type": "sst.sst.Secret"
       "value": string

+ 16 - 0
packages/enterprise/sst-env.d.ts

@@ -34,6 +34,14 @@ declare module "sst" {
       "type": "sst.cloudflare.SolidStart"
       "url": string
     }
+    "DISCORD_SUPPORT_BOT_TOKEN": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "DISCORD_SUPPORT_CHANNEL_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "Database": {
       "database": string
       "host": string
@@ -46,6 +54,14 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "value": string
     }
+    "FEISHU_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "FEISHU_APP_SECRET": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "GITHUB_APP_ID": {
       "type": "sst.sst.Secret"
       "value": string

+ 66 - 0
packages/function/src/api.ts

@@ -12,6 +12,20 @@ type Env = {
   WEB_DOMAIN: string
 }
 
+async function getFeishuTenantToken(): Promise<string> {
+  const response = await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", {
+    method: "POST",
+    headers: { "Content-Type": "application/json" },
+    body: JSON.stringify({
+      app_id: Resource.FEISHU_APP_ID.value,
+      app_secret: Resource.FEISHU_APP_SECRET.value,
+    }),
+  })
+  const data = (await response.json()) as { tenant_access_token?: string }
+  if (!data.tenant_access_token) throw new Error("Failed to get Feishu tenant token")
+  return data.tenant_access_token
+}
+
 export class SyncServer extends DurableObject<Env> {
   constructor(ctx: DurableObjectState, env: Env) {
     super(ctx, env)
@@ -200,6 +214,58 @@ export default new Hono<{ Bindings: Env }>()
 
     return c.json({ info, messages })
   })
+  .post("/feishu", async (c) => {
+    const body = (await c.req.json()) as {
+    challenge?: string
+  event?: {
+    message?: {
+      message_id?: string
+      root_id?: string
+      parent_id?: string
+      chat_id?: string
+      content?: string
+    }
+  }
+}
+    console.log(JSON.stringify(body, null, 2))
+    const challenge = body.challenge
+    if (challenge) return c.json({ challenge })
+
+    const content = body.event?.message?.content
+    const parsed =
+      typeof content === "string" && content.trim().startsWith("{") ? (JSON.parse(content) as {
+  text?: string
+}) : undefined
+    const text = typeof parsed?.text === "string" ? parsed.text : typeof content === "string" ? content : ""
+
+    let message = text.trim().replace(/^@_user_\d+\s*/, "")
+    message = message.replace(/^aiden,?\s*/i, "<@759257817772851260> ")
+    if (!message) return c.json({ ok: true })
+
+    const threadId = body.event?.message?.root_id || body.event?.message?.message_id
+    if (threadId) message = `${message} [${threadId}]`
+
+    const response = await fetch(
+      `https://discord.com/api/v10/channels/${Resource.DISCORD_SUPPORT_CHANNEL_ID.value}/messages`,
+      {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+          Authorization: `Bot ${Resource.DISCORD_SUPPORT_BOT_TOKEN.value}`,
+        },
+        body: JSON.stringify({
+          content: `${message}`,
+        }),
+      },
+    )
+
+    if (!response.ok) {
+      console.error(await response.text())
+      return c.json({ error: "Discord bot message failed" }, { status: 502 })
+    }
+
+    return c.json({ ok: true })
+  })
   /**
    * Used by the GitHub action to get GitHub installation access token given the OIDC token
    */

+ 16 - 0
packages/function/sst-env.d.ts

@@ -34,6 +34,14 @@ declare module "sst" {
       "type": "sst.cloudflare.SolidStart"
       "url": string
     }
+    "DISCORD_SUPPORT_BOT_TOKEN": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "DISCORD_SUPPORT_CHANNEL_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "Database": {
       "database": string
       "host": string
@@ -46,6 +54,14 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "value": string
     }
+    "FEISHU_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "FEISHU_APP_SECRET": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "GITHUB_APP_ID": {
       "type": "sst.sst.Secret"
       "value": string

+ 16 - 0
sst-env.d.ts

@@ -49,6 +49,14 @@ declare module "sst" {
       "type": "sst.cloudflare.SolidStart"
       "url": string
     }
+    "DISCORD_SUPPORT_BOT_TOKEN": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "DISCORD_SUPPORT_CHANNEL_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "Database": {
       "database": string
       "host": string
@@ -65,6 +73,14 @@ declare module "sst" {
       "name": string
       "type": "sst.cloudflare.Bucket"
     }
+    "FEISHU_APP_ID": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
+    "FEISHU_APP_SECRET": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "GITHUB_APP_ID": {
       "type": "sst.sst.Secret"
       "value": string