aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/chats.js
blob: c13564fd3e8d5f52dc16dfe67dff33ec79161e3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import * as ser from '../serialize.js';

const chatParam = { type: 'chat', required: true, description: 'Chat: JID (549...@c.us, ...@g.us), phone number or exact name' };

const simple = (description, fn) => ({
    description,
    params: { chatId: chatParam },
    handler: async (ctx, p) => fn(ctx, p.chatId),
});

export default {
    'chats.list': {
        description: 'Lists chats, most recent first.',
        params: {
            unread: { type: 'boolean', description: 'Only chats with unread messages' },
            archived: { type: 'boolean', description: 'true: archived only; false: unarchived only' },
            groups: { type: 'boolean', description: 'true: solo grupos; false: solo individuales' },
            query: { type: 'string', description: 'Filters by name (case- and accent-insensitive)' },
            limit: { type: 'integer', description: 'Maximum number of chats to return' },
        },
        columns: ['id', 'name', 'unreadCount', 'date', 'lastMessage.body'],
        handler: async (ctx, p) => {
            const norm = ctx.normalize;
            let chats = (await ctx.client.getChats())
                .filter((c) => p.unread === undefined || (c.unreadCount > 0) === p.unread)
                .filter((c) => p.archived === undefined || Boolean(c.archived) === p.archived)
                .filter((c) => p.groups === undefined || Boolean(c.isGroup) === p.groups)
                .filter((c) => !p.query || norm(c.name || '').includes(norm(p.query)))
                .sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
            if (p.limit) chats = chats.slice(0, p.limit);
            return chats.map((c) => ser.chat(c, ctx.ser));
        },
    },

    'chats.get': {
        description: 'Details of a chat (includes participants for groups).',
        params: { chatId: chatParam },
        handler: async (ctx, p) => {
            const c = await ctx.getChat(p.chatId);
            const out = ser.chat(c, ctx.ser);
            if (c.isGroup) Object.assign(out, ser.group(c, ctx.ser));
            return out;
        },
    },

    'chats.resolve': {
        description: 'Resolves a JID, number or name to a chatId (useful in scripts).',
        params: { query: { type: 'string', required: true, description: 'JID, number or name' } },
        handler: async (ctx, p) => {
            const id = await ctx.resolveChat(p.query);
            return { id, name: ctx.names(id) ?? null };
        },
    },

    'chats.read': simple('Marks the chat as read (sends read receipts).', async (ctx, id) => ({
        ok: await ctx.client.sendSeen(id),
    })),
    'chats.unread': simple('Marks the chat as unread.', async (ctx, id) => {
        await ctx.client.markChatUnread(id);
        return { ok: true };
    }),
    'chats.archive': simple('Archives the chat.', async (ctx, id) => ({ archived: await ctx.client.archiveChat(id) })),
    'chats.unarchive': simple('Unarchives the chat.', async (ctx, id) => ({ archived: await ctx.client.unarchiveChat(id) })),
    'chats.pin': simple('Pins the chat.', async (ctx, id) => ({ pinned: await ctx.client.pinChat(id) })),
    'chats.unpin': simple('Unpins the chat.', async (ctx, id) => ({ pinned: await ctx.client.unpinChat(id) })),
    'chats.unmute': simple('Unmutes the chat.', async (ctx, id) => ctx.client.unmuteChat(id)),
    'chats.sync': simple('Asks the phone for the chat history (for chats with few loaded messages).',
        async (ctx, id) => ({ ok: await ctx.client.syncHistory(id) })),

    'chats.mute': {
        description: 'Mutes the chat, forever or until a date.',
        params: {
            chatId: chatParam,
            until: { type: 'string', description: 'ISO 8601 date or epoch seconds; omitted = forever' },
        },
        handler: async (ctx, p) => {
            let date;
            if (p.until) {
                date = /^\d+$/.test(p.until) ? new Date(Number(p.until) * 1000) : new Date(p.until);
                if (Number.isNaN(date.getTime())) throw new ctx.WaError('EINVAL', `invalid date: ${p.until}`);
            }
            return ctx.client.muteChat(p.chatId, date);
        },
    },
};