Add AGENT_READ label functionality and WhatsApp logout endpoint
This commit is contained in:
parent
eee7189867
commit
fed234e448
|
|
@ -1,3 +1,15 @@
|
|||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gmail-tokens-pvc
|
||||
namespace: ai-agents
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Mi
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
|
|
@ -72,7 +84,8 @@ spec:
|
|||
- key: credentials.json
|
||||
path: credentials.json
|
||||
- name: tokens-volume
|
||||
emptyDir: {}
|
||||
persistentVolumeClaim:
|
||||
claimName: gmail-tokens-pvc
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
|
|||
|
|
@ -58,11 +58,32 @@ function loadAuth() {
|
|||
}
|
||||
}
|
||||
|
||||
async function ensureAgentReadLabel(account) {
|
||||
const gmail = google.gmail({ version: 'v1', auth: account.client });
|
||||
const res = await gmail.users.labels.list({ userId: 'me' });
|
||||
const labels = res.data.labels || [];
|
||||
let agentReadLabel = labels.find(l => l.name === 'AGENT_READ');
|
||||
|
||||
if (!agentReadLabel) {
|
||||
console.log(`Creating AGENT_READ label for account ${account.name}...`);
|
||||
const createRes = await gmail.users.labels.create({
|
||||
userId: 'me',
|
||||
requestBody: {
|
||||
name: 'AGENT_READ',
|
||||
labelListVisibility: 'labelShow',
|
||||
messageListVisibility: 'show'
|
||||
}
|
||||
});
|
||||
agentReadLabel = createRes.data;
|
||||
}
|
||||
return agentReadLabel.id;
|
||||
}
|
||||
|
||||
async function getUnreadEmails(account) {
|
||||
const gmail = google.gmail({ version: 'v1', auth: account.client });
|
||||
const res = await gmail.users.messages.list({
|
||||
userId: 'me',
|
||||
q: 'is:unread',
|
||||
q: 'is:unread -label:AGENT_READ',
|
||||
maxResults: 10
|
||||
});
|
||||
|
||||
|
|
@ -90,18 +111,21 @@ async function getUnreadEmails(account) {
|
|||
return emails;
|
||||
}
|
||||
|
||||
async function markAsRead(email) {
|
||||
async function markAsAgentRead(email, labelId) {
|
||||
const gmail = google.gmail({ version: 'v1', auth: email.client });
|
||||
await gmail.users.messages.modify({
|
||||
userId: 'me',
|
||||
id: email.id,
|
||||
requestBody: { removeLabelIds: ['UNREAD'] }
|
||||
requestBody: { addLabelIds: [labelId] }
|
||||
});
|
||||
}
|
||||
|
||||
async function analyzeWithOllama(email) {
|
||||
const prompt = `You are an AI assistant that determines if an email is important enough to notify the user immediately on WhatsApp.
|
||||
Newsletters, marketing, promotions, and generic updates are NOT important.
|
||||
|
||||
CRITICAL INSTRUCTION: You MUST strictly IGNORE all promotional emails, newsletters, marketing, discounts, product updates, or any emails of low significance.
|
||||
For these, you MUST output IMPORTANT: NO.
|
||||
|
||||
Important things: Bills due, flight/travel updates, urgent requests from people, security alerts, direct personal messages.
|
||||
|
||||
Email Subject: ${email.subject}
|
||||
|
|
@ -166,6 +190,10 @@ async function processEmails() {
|
|||
try {
|
||||
for (const account of accounts) {
|
||||
console.log(`Checking account: ${account.name}...`);
|
||||
if (!account.agentReadLabelId) {
|
||||
account.agentReadLabelId = await ensureAgentReadLabel(account);
|
||||
}
|
||||
|
||||
const emails = await getUnreadEmails(account);
|
||||
if (emails.length === 0) {
|
||||
console.log(`No new emails for ${account.name}.`);
|
||||
|
|
@ -181,8 +209,8 @@ async function processEmails() {
|
|||
} else {
|
||||
console.log(`Skipped non-important email: ${email.subject}`);
|
||||
}
|
||||
// Mark as read so we don't process it again
|
||||
await markAsRead(email);
|
||||
// Mark as processed using our custom label
|
||||
await markAsAgentRead(email, account.agentReadLabelId);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,25 @@ const groupsTableBody = document.getElementById('groups-table-body');
|
|||
const appsTableBody = document.getElementById('apps-table-body');
|
||||
const inviteModal = document.getElementById('invite-modal');
|
||||
const inviteLinkInput = document.getElementById('invite-link-input');
|
||||
const logoutBtn = document.getElementById('logout-btn');
|
||||
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener('click', async () => {
|
||||
const confirmLogout = confirm('Are you sure you want to log out and change your WhatsApp account? This will disconnect the current session and restart the gateway.');
|
||||
if (!confirmLogout) return;
|
||||
|
||||
logoutBtn.disabled = true;
|
||||
logoutBtn.textContent = 'Logging out...';
|
||||
|
||||
try {
|
||||
await fetch('api/whatsapp/logout', { method: 'POST' });
|
||||
alert('Logout initiated! The WhatsApp Gateway is restarting. Please wait 5-10 seconds and then hard-refresh the page to scan a new QR code.');
|
||||
} catch (err) {
|
||||
console.error('Logout error:', err);
|
||||
alert('Failed to log out cleanly, but restarting anyway. Please refresh.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Tab Switching
|
||||
document.querySelectorAll('.nav-btn').forEach(btn => {
|
||||
|
|
@ -39,7 +58,11 @@ function logActivity(msg, type = 'info') {
|
|||
// Socket Events
|
||||
socket.on('status', (data) => {
|
||||
updateStatus(data.ready);
|
||||
if (data.qr && !data.ready) renderQR(data.qr);
|
||||
if (data.ready) {
|
||||
qrContainer.innerHTML = '<h3>✅ Connected</h3><p>Session is active and authenticated.</p>';
|
||||
} else if (data.qr) {
|
||||
renderQR(data.qr);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('qr', (qr) => {
|
||||
|
|
@ -66,9 +89,11 @@ function updateStatus(isReady) {
|
|||
if (isReady) {
|
||||
statusBadge.textContent = 'Connected';
|
||||
statusBadge.className = 'badge success';
|
||||
if (logoutBtn) logoutBtn.style.display = 'block';
|
||||
} else {
|
||||
statusBadge.textContent = 'Disconnected';
|
||||
statusBadge.className = 'badge error';
|
||||
if (logoutBtn) logoutBtn.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@
|
|||
<section id="status" class="tab-pane active">
|
||||
<header>
|
||||
<h2>Connection Status</h2>
|
||||
<div id="status-badge" class="badge error">Disconnected</div>
|
||||
<div style="display:flex; gap:10px; align-items:center;">
|
||||
<button id="logout-btn" class="btn" style="background-color: #ef4444; color: white; display: none; padding: 0.25rem 0.75rem; font-size: 0.875rem;">Logout & Change WhatsApp</button>
|
||||
<div id="status-badge" class="badge error">Disconnected</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="card status-card">
|
||||
|
|
|
|||
|
|
@ -107,6 +107,24 @@ app.get('/api/status', (req, res) => {
|
|||
});
|
||||
});
|
||||
|
||||
app.post('/api/whatsapp/logout', async (req, res) => {
|
||||
try {
|
||||
console.log('[WhatsApp Bot] Logging out...');
|
||||
if (client.info) {
|
||||
await client.logout();
|
||||
}
|
||||
res.json({ success: true, message: 'Logged out successfully. Pod restarting...' });
|
||||
|
||||
// Wait briefly to allow the response to be sent, then exit so Kubernetes restarts the pod cleanly
|
||||
setTimeout(() => process.exit(0), 1000);
|
||||
} catch (err) {
|
||||
console.error('Logout error:', err);
|
||||
res.status(500).json({ success: false, error: err.message });
|
||||
// Still exit to force a clean slate
|
||||
setTimeout(() => process.exit(1), 1000);
|
||||
}
|
||||
});
|
||||
|
||||
// ─── App Tracking ───────────────────────────────────────────────────────────
|
||||
const connectedApps = {};
|
||||
|
||||
|
|
@ -235,6 +253,7 @@ app.post('/api/groups/add-by-link', async (req, res) => {
|
|||
|
||||
res.json({ success: true, group: newGroup });
|
||||
} catch (err) {
|
||||
console.error('[Add Group Error]:', err);
|
||||
res.status(500).json({ error: err.message || 'Failed to process invite link' });
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue