feat: add telegram business connect onboarding and status sync
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { readBody } from "h3";
|
||||
import { getAuthContext } from "../../../../../utils/auth";
|
||||
import { prisma } from "../../../../../utils/prisma";
|
||||
import { telegramBotApi } from "../../../../../utils/telegram";
|
||||
|
||||
type RefreshBody = {
|
||||
businessConnectionId?: string;
|
||||
};
|
||||
|
||||
function mapFlags(raw: any) {
|
||||
const isEnabled = typeof raw?.is_enabled === "boolean" ? raw.is_enabled : null;
|
||||
const canReply = typeof raw?.can_reply === "boolean"
|
||||
? raw.can_reply
|
||||
: typeof raw?.rights?.can_reply === "boolean"
|
||||
? raw.rights.can_reply
|
||||
: null;
|
||||
return { isEnabled, canReply };
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const auth = await getAuthContext(event);
|
||||
const body = await readBody<RefreshBody>(event);
|
||||
|
||||
const businessConnectionId = String(body?.businessConnectionId ?? "").trim();
|
||||
if (!businessConnectionId) {
|
||||
throw createError({ statusCode: 400, statusMessage: "businessConnectionId is required" });
|
||||
}
|
||||
|
||||
const existing = await prisma.telegramBusinessConnection.findFirst({
|
||||
where: {
|
||||
teamId: auth.teamId,
|
||||
businessConnectionId,
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (!existing) {
|
||||
throw createError({ statusCode: 404, statusMessage: "business connection not found" });
|
||||
}
|
||||
|
||||
const response = await telegramBotApi<any>("getBusinessConnection", { business_connection_id: businessConnectionId });
|
||||
const { isEnabled, canReply } = mapFlags(response);
|
||||
|
||||
const updated = await prisma.telegramBusinessConnection.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
isEnabled,
|
||||
canReply,
|
||||
rawJson: {
|
||||
state: "connected",
|
||||
refreshedAt: new Date().toISOString(),
|
||||
businessConnection: response,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
businessConnectionId: true,
|
||||
isEnabled: true,
|
||||
canReply: true,
|
||||
updatedAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
connection: {
|
||||
businessConnectionId: updated.businessConnectionId,
|
||||
isEnabled: updated.isEnabled,
|
||||
canReply: updated.canReply,
|
||||
updatedAt: updated.updatedAt.toISOString(),
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { getAuthContext } from "../../../../../utils/auth";
|
||||
import { prisma } from "../../../../../utils/prisma";
|
||||
import { buildTelegramStartUrl, issueLinkToken } from "../../../../../utils/telegramBusinessConnect";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const auth = await getAuthContext(event);
|
||||
const { token, payload } = issueLinkToken({ teamId: auth.teamId, userId: auth.userId });
|
||||
|
||||
const pendingId = `pending:${payload.nonce}`;
|
||||
await prisma.telegramBusinessConnection.upsert({
|
||||
where: {
|
||||
teamId_businessConnectionId: {
|
||||
teamId: auth.teamId,
|
||||
businessConnectionId: pendingId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
teamId: auth.teamId,
|
||||
businessConnectionId: pendingId,
|
||||
rawJson: {
|
||||
state: "pending_link",
|
||||
link: {
|
||||
nonce: payload.nonce,
|
||||
exp: payload.exp,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdByUserId: auth.userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {
|
||||
isEnabled: null,
|
||||
canReply: null,
|
||||
rawJson: {
|
||||
state: "pending_link",
|
||||
link: {
|
||||
nonce: payload.nonce,
|
||||
exp: payload.exp,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdByUserId: auth.userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
status: "pending_link",
|
||||
connectUrl: buildTelegramStartUrl(token),
|
||||
expiresAt: new Date(payload.exp * 1000).toISOString(),
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import { getAuthContext } from "../../../../../utils/auth";
|
||||
import { prisma } from "../../../../../utils/prisma";
|
||||
|
||||
function normalizeStatus(input: {
|
||||
pendingCount: number;
|
||||
linkedPendingCount: number;
|
||||
connectedCount: number;
|
||||
enabledCount: number;
|
||||
replyEnabledCount: number;
|
||||
}) {
|
||||
if (input.connectedCount > 0) {
|
||||
if (input.replyEnabledCount > 0 && input.enabledCount > 0) return "connected";
|
||||
if (input.enabledCount === 0) return "disabled";
|
||||
return "no_reply_rights";
|
||||
}
|
||||
if (input.linkedPendingCount > 0) return "pending_business_connection";
|
||||
if (input.pendingCount > 0) return "pending_link";
|
||||
return "not_connected";
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const auth = await getAuthContext(event);
|
||||
const rows = await prisma.telegramBusinessConnection.findMany({
|
||||
where: { teamId: auth.teamId },
|
||||
orderBy: { updatedAt: "desc" },
|
||||
take: 50,
|
||||
});
|
||||
|
||||
const pending = rows.filter((r) => r.businessConnectionId.startsWith("pending:"));
|
||||
const active = rows.filter((r) => !r.businessConnectionId.startsWith("pending:"));
|
||||
|
||||
const linkedPendingCount = pending.filter((r) => {
|
||||
const raw = (r.rawJson ?? {}) as any;
|
||||
return Boolean(raw?.link?.telegramUserId || raw?.link?.chatId);
|
||||
}).length;
|
||||
|
||||
const enabledCount = active.filter((r) => r.isEnabled !== false).length;
|
||||
const replyEnabledCount = active.filter((r) => r.canReply === true).length;
|
||||
|
||||
const status = normalizeStatus({
|
||||
pendingCount: pending.length,
|
||||
linkedPendingCount,
|
||||
connectedCount: active.length,
|
||||
enabledCount,
|
||||
replyEnabledCount,
|
||||
});
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
status,
|
||||
pendingCount: pending.length,
|
||||
connectedCount: active.length,
|
||||
connections: active.map((r) => ({
|
||||
businessConnectionId: r.businessConnectionId,
|
||||
isEnabled: r.isEnabled,
|
||||
canReply: r.canReply,
|
||||
updatedAt: r.updatedAt.toISOString(),
|
||||
})),
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user