Whatsapp unlink WIP #1
This commit is contained in:
parent
12b72a727c
commit
48165db6a2
9 changed files with 120 additions and 3 deletions
|
|
@ -0,0 +1 @@
|
||||||
|
export { relinkBot as POST } from "@link-stack/bridge-ui";
|
||||||
|
|
@ -286,8 +286,30 @@ export default class WhatsappService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
async unverify(botID: string): Promise<void> {
|
async unverify(botID: string): Promise<void> {
|
||||||
|
// Step 1: Close and remove the active connection if it exists
|
||||||
|
const connection = this.connections[botID];
|
||||||
|
if (connection?.socket) {
|
||||||
|
try {
|
||||||
|
// Properly close the WebSocket connection
|
||||||
|
await connection.socket.logout();
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn({ botID, error }, "Error during logout, forcing disconnect");
|
||||||
|
try {
|
||||||
|
connection.socket.end(undefined);
|
||||||
|
} catch (endError) {
|
||||||
|
logger.warn({ botID, endError }, "Error ending socket connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Remove from in-memory connections
|
||||||
|
delete this.connections[botID];
|
||||||
|
|
||||||
|
// Step 3: Remove the bot directory (auth state, QR code, verified marker)
|
||||||
const botDirectory = this.getBotDirectory(botID);
|
const botDirectory = this.getBotDirectory(botID);
|
||||||
fs.rmSync(botDirectory, { recursive: true, force: true });
|
if (fs.existsSync(botDirectory)) {
|
||||||
|
fs.rmSync(botDirectory, { recursive: true, force: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(
|
async register(
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ const sendSignalMessageTask = async ({
|
||||||
{
|
{
|
||||||
number,
|
number,
|
||||||
recipients: [finalTo],
|
recipients: [finalTo],
|
||||||
message: message.substring(0, 50) + "...",
|
messageLength: message?.length,
|
||||||
hasQuoteParams: !!(quoteMessage && quoteAuthor && quoteTimestamp),
|
hasQuoteParams: !!(quoteMessage && quoteAuthor && quoteTimestamp),
|
||||||
},
|
},
|
||||||
"Message data being sent",
|
"Message data being sent",
|
||||||
|
|
@ -197,7 +197,7 @@ const sendSignalMessageTask = async ({
|
||||||
logger.debug(
|
logger.debug(
|
||||||
{
|
{
|
||||||
quoteAuthor,
|
quoteAuthor,
|
||||||
quoteMessage: quoteMessage.substring(0, 50) + "...",
|
quoteMessageLength: quoteMessage?.length,
|
||||||
quoteTimestamp,
|
quoteTimestamp,
|
||||||
},
|
},
|
||||||
"Including quote in message",
|
"Including quote in message",
|
||||||
|
|
|
||||||
1
apps/link/app/api/[service]/bots/[token]/relink/route.ts
Normal file
1
apps/link/app/api/[service]/bots/[token]/relink/route.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { relinkBot as POST } from "@link-stack/bridge-ui";
|
||||||
|
|
@ -34,6 +34,8 @@ export const Detail: FC<DetailProps> = ({ service, row }) => {
|
||||||
const { almostBlack } = colors;
|
const { almostBlack } = colors;
|
||||||
const { bodyLarge } = typography;
|
const { bodyLarge } = typography;
|
||||||
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
|
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
|
||||||
|
const [showRelinkConfirmation, setShowRelinkConfirmation] = useState(false);
|
||||||
|
const [isRelinking, setIsRelinking] = useState(false);
|
||||||
|
|
||||||
const continueDeleteAction = async () => {
|
const continueDeleteAction = async () => {
|
||||||
await deleteAction?.(id);
|
await deleteAction?.(id);
|
||||||
|
|
@ -41,6 +43,23 @@ export const Detail: FC<DetailProps> = ({ service, row }) => {
|
||||||
router.push(`${getBasePath()}${entity}`);
|
router.push(`${getBasePath()}${entity}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const continueRelinkAction = async () => {
|
||||||
|
setIsRelinking(true);
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/link/api/${entity}/bots/${token}/relink`, {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
setShowRelinkConfirmation(false);
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Relink failed:", error);
|
||||||
|
} finally {
|
||||||
|
setIsRelinking(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dialog
|
<Dialog
|
||||||
|
|
@ -57,6 +76,15 @@ export const Detail: FC<DetailProps> = ({ service, row }) => {
|
||||||
onClick={() => setShowDeleteConfirmation(true)}
|
onClick={() => setShowDeleteConfirmation(true)}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{service === "whatsapp" && (
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
text="Relink"
|
||||||
|
kind="secondary"
|
||||||
|
onClick={() => setShowRelinkConfirmation(true)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Button
|
<Button
|
||||||
text="Edit"
|
text="Edit"
|
||||||
|
|
@ -129,6 +157,35 @@ export const Detail: FC<DetailProps> = ({ service, row }) => {
|
||||||
Are you sure you want to delete this record?
|
Are you sure you want to delete this record?
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<Dialog
|
||||||
|
open={showRelinkConfirmation}
|
||||||
|
size="xs"
|
||||||
|
title="Relink WhatsApp Connection?"
|
||||||
|
buttons={
|
||||||
|
<Grid container justifyContent="space-between">
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
text="Cancel"
|
||||||
|
kind="secondary"
|
||||||
|
onClick={() => setShowRelinkConfirmation(false)}
|
||||||
|
disabled={isRelinking}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
text={isRelinking ? "Relinking..." : "Relink"}
|
||||||
|
kind="primary"
|
||||||
|
onClick={continueRelinkAction}
|
||||||
|
disabled={isRelinking}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box sx={{ ...bodyLarge, color: almostBlack }}>
|
||||||
|
This will disconnect the current WhatsApp link and generate a new QR code. You will need to scan the new QR code to reconnect. Continue?
|
||||||
|
</Box>
|
||||||
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,5 @@ export {
|
||||||
sendMessage,
|
sendMessage,
|
||||||
receiveMessage,
|
receiveMessage,
|
||||||
handleWebhook,
|
handleWebhook,
|
||||||
|
relinkBot,
|
||||||
} from "./lib/routing";
|
} from "./lib/routing";
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,8 @@ export const handleWebhook = async (
|
||||||
req: NextRequest,
|
req: NextRequest,
|
||||||
params: ServiceParams,
|
params: ServiceParams,
|
||||||
): Promise<NextResponse> => (await getService(params))?.handleWebhook(req);
|
): Promise<NextResponse> => (await getService(params))?.handleWebhook(req);
|
||||||
|
|
||||||
|
export const relinkBot = async (
|
||||||
|
_req: NextRequest,
|
||||||
|
params: ServiceParams,
|
||||||
|
): Promise<NextResponse> => (await getService(params))?.relink(params);
|
||||||
|
|
|
||||||
|
|
@ -122,4 +122,8 @@ export class Service {
|
||||||
async handleWebhook(_req: NextRequest): Promise<NextResponse> {
|
async handleWebhook(_req: NextRequest): Promise<NextResponse> {
|
||||||
return NextResponse.error() as any;
|
return NextResponse.error() as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async relink({ params: _params }: ServiceParams): Promise<NextResponse> {
|
||||||
|
return NextResponse.error() as any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,4 +31,30 @@ export class Whatsapp extends Service {
|
||||||
|
|
||||||
return NextResponse.json(json);
|
return NextResponse.json(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async relink({ params }: ServiceParams) {
|
||||||
|
const { token } = await params;
|
||||||
|
const row = await db
|
||||||
|
.selectFrom("WhatsappBot")
|
||||||
|
.selectAll()
|
||||||
|
.where("token", "=", token as string)
|
||||||
|
.executeTakeFirstOrThrow();
|
||||||
|
const id = row.id;
|
||||||
|
|
||||||
|
// Step 1: Call unverify to remove the bot directory and disconnect
|
||||||
|
const unverifyUrl = `${process.env.BRIDGE_WHATSAPP_URL}/api/bots/${id}/unverify`;
|
||||||
|
await fetch(unverifyUrl, { method: "POST" });
|
||||||
|
|
||||||
|
// Step 2: Reset verified flag in database
|
||||||
|
await db
|
||||||
|
.updateTable("WhatsappBot")
|
||||||
|
.set({ verified: false })
|
||||||
|
.where("id", "=", id)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
// Step 3: Revalidate the path to refresh the UI
|
||||||
|
revalidatePath(`/whatsapp/${id}`);
|
||||||
|
|
||||||
|
return NextResponse.json({ success: true, message: "WhatsApp connection reset. Please scan the new QR code." });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue