diff --git a/app/components/webhooks/WebhookFormModal.vue b/app/components/webhooks/WebhookFormModal.vue index 14ddc18..dfe7ccc 100644 --- a/app/components/webhooks/WebhookFormModal.vue +++ b/app/components/webhooks/WebhookFormModal.vue @@ -42,13 +42,19 @@
- + class="flex items-center gap-2 cursor-pointer text-sm text-[var(--wa-text)]" + > + + {{ event.label }} +
@@ -145,6 +151,15 @@ const isValid = computed(() => { return form.value.name.trim() && form.value.url.trim() && form.value.events.length > 0 }) +const toggleEvent = (eventValue: string) => { + const index = form.value.events.indexOf(eventValue) + if (index === -1) { + form.value.events.push(eventValue) + } else { + form.value.events.splice(index, 1) + } +} + // Watch for webhook changes to populate form watch(() => props.webhook, (webhook) => { if (webhook) { diff --git a/server/api/debug/blocklist/index.get.ts b/server/api/debug/blocklist/index.get.ts new file mode 100644 index 0000000..1e0640b --- /dev/null +++ b/server/api/debug/blocklist/index.get.ts @@ -0,0 +1,34 @@ +/** + * GET /api/debug/blocklist + * Fetch the blocklist for an instance + */ +import { baileysManager } from '../../../services/baileys/manager' + +export default defineEventHandler(async (event) => { + const username = getHeader(event, 'x-authentik-username') + if (!username) { + throw createError({ statusCode: 401, message: 'Unauthorized' }) + } + + const query = getQuery(event) + const instanceId = query.instanceId as string + + if (!instanceId) { + throw createError({ statusCode: 400, message: 'instanceId is required' }) + } + + const socket = baileysManager.getSocket(instanceId) + if (!socket) { + throw createError({ statusCode: 400, message: 'Instance not connected' }) + } + + try { + const result = await socket.fetchBlocklist() + return { success: true, data: result } + } catch (error) { + throw createError({ + statusCode: 500, + message: `Failed to fetch blocklist: ${(error as Error).message}` + }) + } +}) diff --git a/server/api/debug/blocklist/update.post.ts b/server/api/debug/blocklist/update.post.ts new file mode 100644 index 0000000..9ef3cd7 --- /dev/null +++ b/server/api/debug/blocklist/update.post.ts @@ -0,0 +1,42 @@ +/** + * POST /api/debug/blocklist/update + * Block or unblock a JID + */ +import { baileysManager } from '../../../services/baileys/manager' + +export default defineEventHandler(async (event) => { + const username = getHeader(event, 'x-authentik-username') + if (!username) { + throw createError({ statusCode: 401, message: 'Unauthorized' }) + } + + const body = await readBody(event) + const { instanceId, jid, action } = body + + if (!instanceId) { + throw createError({ statusCode: 400, message: 'instanceId is required' }) + } + + if (!jid) { + throw createError({ statusCode: 400, message: 'jid is required' }) + } + + if (!action || !['block', 'unblock'].includes(action)) { + throw createError({ statusCode: 400, message: 'action must be "block" or "unblock"' }) + } + + const socket = baileysManager.getSocket(instanceId) + if (!socket) { + throw createError({ statusCode: 400, message: 'Instance not connected' }) + } + + try { + await socket.updateBlockStatus(jid, action) + return { success: true, message: `User ${action}ed successfully` } + } catch (error) { + throw createError({ + statusCode: 500, + message: `Failed to ${action} user: ${(error as Error).message}` + }) + } +}) diff --git a/server/api/debug/privacy/index.get.ts b/server/api/debug/privacy/index.get.ts new file mode 100644 index 0000000..265b2dd --- /dev/null +++ b/server/api/debug/privacy/index.get.ts @@ -0,0 +1,34 @@ +/** + * GET /api/debug/privacy + * Fetch privacy settings for an instance + */ +import { baileysManager } from '../../../services/baileys/manager' + +export default defineEventHandler(async (event) => { + const username = getHeader(event, 'x-authentik-username') + if (!username) { + throw createError({ statusCode: 401, message: 'Unauthorized' }) + } + + const query = getQuery(event) + const instanceId = query.instanceId as string + + if (!instanceId) { + throw createError({ statusCode: 400, message: 'instanceId is required' }) + } + + const socket = baileysManager.getSocket(instanceId) + if (!socket) { + throw createError({ statusCode: 400, message: 'Instance not connected' }) + } + + try { + const result = await socket.fetchPrivacySettings(true) + return { success: true, data: result } + } catch (error) { + throw createError({ + statusCode: 500, + message: `Failed to fetch privacy settings: ${(error as Error).message}` + }) + } +}) diff --git a/server/api/debug/privacy/update.post.ts b/server/api/debug/privacy/update.post.ts new file mode 100644 index 0000000..54570c1 --- /dev/null +++ b/server/api/debug/privacy/update.post.ts @@ -0,0 +1,72 @@ +/** + * POST /api/debug/privacy/update + * Update a privacy setting + */ +import { baileysManager } from '../../../services/baileys/manager' + +type PrivacySetting = 'lastSeen' | 'online' | 'profilePicture' | 'status' | 'groupsAdd' | 'readReceipts' + +export default defineEventHandler(async (event) => { + const username = getHeader(event, 'x-authentik-username') + if (!username) { + throw createError({ statusCode: 401, message: 'Unauthorized' }) + } + + const body = await readBody(event) + const { instanceId, setting, value } = body as { instanceId: string; setting: PrivacySetting; value: string } + + if (!instanceId) { + throw createError({ statusCode: 400, message: 'instanceId is required' }) + } + + if (!setting) { + throw createError({ statusCode: 400, message: 'setting is required' }) + } + + if (!value) { + throw createError({ statusCode: 400, message: 'value is required' }) + } + + const validSettings: PrivacySetting[] = ['lastSeen', 'online', 'profilePicture', 'status', 'groupsAdd', 'readReceipts'] + if (!validSettings.includes(setting)) { + throw createError({ + statusCode: 400, + message: `Invalid setting. Must be one of: ${validSettings.join(', ')}` + }) + } + + const socket = baileysManager.getSocket(instanceId) + if (!socket) { + throw createError({ statusCode: 400, message: 'Instance not connected' }) + } + + try { + switch (setting) { + case 'lastSeen': + await socket.updateLastSeenPrivacy(value as any) + break + case 'online': + await socket.updateOnlinePrivacy(value as any) + break + case 'profilePicture': + await socket.updateProfilePicturePrivacy(value as any) + break + case 'status': + await socket.updateStatusPrivacy(value as any) + break + case 'groupsAdd': + await socket.updateGroupsAddPrivacy(value as any) + break + case 'readReceipts': + await socket.updateReadReceiptsPrivacy(value as any) + break + } + + return { success: true, message: `Privacy setting "${setting}" updated to "${value}"` } + } catch (error) { + throw createError({ + statusCode: 500, + message: `Failed to update privacy setting: ${(error as Error).message}` + }) + } +}) diff --git a/server/services/baileys/manager.ts b/server/services/baileys/manager.ts index 45e83c6..6e84df5 100644 --- a/server/services/baileys/manager.ts +++ b/server/services/baileys/manager.ts @@ -465,6 +465,18 @@ class BaileysManager extends EventEmitter { return Array.from(this.instances.values()) } + /** + * Get the raw socket for an instance (for debug purposes) + * Returns null if instance is not connected + */ + getSocket(instanceId: string): WASocket | null { + const managed = this.instances.get(instanceId) + if (!managed || managed.status !== 'connected') { + return null + } + return managed.socket + } + /** * Update instance status in database */