Compare commits

...

7 Commits

Author SHA1 Message Date
Rajeh Taher
4d72ea3b60 Merge branch 'main' into add-polls 2023-01-05 23:10:26 +02:00
Rajeh Taher
eaa27ff228 Merge branch 'main' into add-polls 2022-12-24 00:05:19 +02:00
purpshell
17f245485d bugfix 2022-12-23 15:09:44 +02:00
purpshell
93c8ff7165 fix circular dep. 2022-12-23 14:54:44 +02:00
Rajeh Taher
a0877ea60b urgent fix 2022-12-23 13:17:28 +02:00
purpshell
2020d00ee4 PART 2: ESLINT, EXAMPLES & MORE 2022-12-23 13:09:01 +02:00
purpshell
a519105870 Poll implementation 2022-12-23 12:37:07 +02:00
8 changed files with 235 additions and 53 deletions

View File

@@ -197,6 +197,27 @@ client.on('message', async msg => {
client.sendMessage(msg.from, list); client.sendMessage(msg.from, list);
} else if (msg.body === '!reaction') { } else if (msg.body === '!reaction') {
msg.react('👍'); msg.react('👍');
} else if (msg.body.startsWith('!vote ')) {
if (msg.hasQuotedMsg) {
const quotedMsg = await msg.getQuotedMessage();
if (quotedMsg.type === 'poll_creation') {
const options = msg.body.slice(6).split('//');
const voteCount = {};
for (const pollVote of quotedMsg.pollVotes) {
for (const selectedOption of pollVote.selectedOptions) {
if (!voteCount[selectedOption]) voteCount[selectedOption] = 0;
voteCount[selectedOption]++;
}
}
const voteCountStr = Object.entries(voteCount).map(([vote, number]) => ` -${vote}: ${number}`).join('\n');
quotedMsg.reply(
`Voting to poll ${quotedMsg.body}, with options: ${options.join(', ')}\ncurrent vote count:\n${voteCountStr}`
);
quotedMsg.vote(options);
} else {
msg.reply('Usage: !vote TEST1//TEST2');
}
}
} }
}); });
@@ -253,6 +274,10 @@ client.on('group_update', (notification) => {
console.log('update', notification); console.log('update', notification);
}); });
client.on('poll_vote', (vote) => {
console.log(`Vote received, from ${vote.sender}, ${vote.selectedOptions.map(a => ` - ${a}`).join('\n')}`);
});
client.on('change_state', state => { client.on('change_state', state => {
console.log('CHANGE STATE', state ); console.log('CHANGE STATE', state );
}); });

30
index.d.ts vendored
View File

@@ -2,6 +2,7 @@
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { RequestInit } from 'node-fetch' import { RequestInit } from 'node-fetch'
import * as puppeteer from 'puppeteer' import * as puppeteer from 'puppeteer'
import PollVote from './src/structures/PollVote'
declare namespace WAWebJS { declare namespace WAWebJS {
@@ -268,6 +269,12 @@ declare namespace WAWebJS {
/** Emitted when the RemoteAuth session is saved successfully on the external Database */ /** Emitted when the RemoteAuth session is saved successfully on the external Database */
on(event: 'remote_session_saved', listener: () => void): this on(event: 'remote_session_saved', listener: () => void): this
/** Emitted when a poll vote is received */
on(event: 'poll_vote', listener: (
/** The poll vote */
vote: PollVote
) => void): this
} }
/** Current connection information */ /** Current connection information */
@@ -506,7 +513,8 @@ declare namespace WAWebJS {
DISCONNECTED = 'disconnected', DISCONNECTED = 'disconnected',
STATE_CHANGED = 'change_state', STATE_CHANGED = 'change_state',
BATTERY_CHANGED = 'change_battery', BATTERY_CHANGED = 'change_battery',
REMOTE_SESSION_SAVED = 'remote_session_saved' REMOTE_SESSION_SAVED = 'remote_session_saved',
POLL_VOTE = 'poll_vote'
} }
/** Group notification types */ /** Group notification types */
@@ -569,6 +577,7 @@ declare namespace WAWebJS {
PROTOCOL = 'protocol', PROTOCOL = 'protocol',
REACTION = 'reaction', REACTION = 'reaction',
TEMPLATE_BUTTON_REPLY = 'template_button_reply', TEMPLATE_BUTTON_REPLY = 'template_button_reply',
POLL_CREATION = 'poll_creation',
} }
/** Client status */ /** Client status */
@@ -721,6 +730,10 @@ declare namespace WAWebJS {
selectedRowId?: string, selectedRowId?: string,
/** Returns message in a raw format */ /** Returns message in a raw format */
rawData: object, rawData: object,
/** Avaiaible poll voting options */
pollOptions: string[],
/** The current poll votes, refresh with .refreshPollVotes() */
pollVotes: PollVote[],
/* /*
* Reloads this Message object's data in-place with the latest values from WhatsApp Web. * Reloads this Message object's data in-place with the latest values from WhatsApp Web.
* Note that the Message must still be in the web app cache for this to work, otherwise will return null. * Note that the Message must still be in the web app cache for this to work, otherwise will return null.
@@ -766,6 +779,15 @@ declare namespace WAWebJS {
* Gets the payment details associated with a given message * Gets the payment details associated with a given message
*/ */
getPayment: () => Promise<Payment>, getPayment: () => Promise<Payment>,
/**
* Refreshes the current poll votes, only works with a poll_creation message
*/
refreshPollVotes: () => Promise<void>,
/**
* Vote on the poll, only works with a poll_creation message
* @param {Array<string>} selectedOptions The selected options from .pollOptions
*/
vote: (selectedOptions: string[]) => Promise<void>,
} }
/** ID that represents a message */ /** ID that represents a message */
@@ -1364,6 +1386,12 @@ declare namespace WAWebJS {
senderId: string senderId: string
ack?: number ack?: number
} }
export class PollVote {
selectedOptions: string[]
sender: string
senderTimestampMs: number
}
} }
export = WAWebJS export = WAWebJS

View File

@@ -21,12 +21,15 @@ module.exports = {
ProductMetadata: require('./src/structures/ProductMetadata'), ProductMetadata: require('./src/structures/ProductMetadata'),
List: require('./src/structures/List'), List: require('./src/structures/List'),
Buttons: require('./src/structures/Buttons'), Buttons: require('./src/structures/Buttons'),
PollVote: require('./src/structures/PollVote'),
Call: require('./src/structures/Call'),
// Auth Strategies // Auth Strategies
NoAuth: require('./src/authStrategies/NoAuth'), NoAuth: require('./src/authStrategies/NoAuth'),
LocalAuth: require('./src/authStrategies/LocalAuth'), LocalAuth: require('./src/authStrategies/LocalAuth'),
RemoteAuth: require('./src/authStrategies/RemoteAuth'), RemoteAuth: require('./src/authStrategies/RemoteAuth'),
LegacySessionAuth: require('./src/authStrategies/LegacySessionAuth'), LegacySessionAuth: require('./src/authStrategies/LegacySessionAuth'),
...Constants ...Constants
}; };

View File

@@ -13,6 +13,7 @@ const ContactFactory = require('./factories/ContactFactory');
const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures'); const { ClientInfo, Message, MessageMedia, Contact, Location, GroupNotification, Label, Call, Buttons, List, Reaction } = require('./structures');
const LegacySessionAuth = require('./authStrategies/LegacySessionAuth'); const LegacySessionAuth = require('./authStrategies/LegacySessionAuth');
const NoAuth = require('./authStrategies/NoAuth'); const NoAuth = require('./authStrategies/NoAuth');
const PollVote = require('./structures/PollVote');
/** /**
* Starting point for interacting with the WhatsApp Web API * Starting point for interacting with the WhatsApp Web API
@@ -45,6 +46,7 @@ const NoAuth = require('./authStrategies/NoAuth');
* @fires Client#group_update * @fires Client#group_update
* @fires Client#disconnected * @fires Client#disconnected
* @fires Client#change_state * @fires Client#change_state
* @fires
*/ */
class Client extends EventEmitter { class Client extends EventEmitter {
constructor(options = {}) { constructor(options = {}) {
@@ -83,7 +85,14 @@ class Client extends EventEmitter {
* Sets up events and requirements, kicks off authentication request * Sets up events and requirements, kicks off authentication request
*/ */
async initialize() { async initialize() {
let [browser, page] = [null, null]; /**
* @type {puppeteer.Browser}
*/
let browser = null;
/**
* @type {puppeteer.Page}
*/
let page = null;
await this.authStrategy.beforeBrowserInitialized(); await this.authStrategy.beforeBrowserInitialized();
@@ -486,6 +495,19 @@ class Client extends EventEmitter {
this.emit(Events.INCOMING_CALL, cll); this.emit(Events.INCOMING_CALL, cll);
}); });
await page.exposeFunction('onPollVote', (vote) => {
const vote_ = new PollVote(this, vote);
/**
* Emitted when a poll vote is received
* @event Client#poll_vote
* @param {object} vote
* @param {string} vote.sender Sender of the vote
* @param {number} vote.senderTimestampMs Timestamp the vote was sent
* @param {Array<string>} vote.selectedOptions Options selected
*/
this.emit(Events.POLL_VOTE, vote_);
});
await page.exposeFunction('onReaction', (reactions) => { await page.exposeFunction('onReaction', (reactions) => {
for (const reaction of reactions) { for (const reaction of reactions) {
/** /**
@@ -526,7 +548,12 @@ class Client extends EventEmitter {
} }
} }
}); });
window.Store.PollVote.on('add', (vote) => {
if (vote.parentMsgKey) vote.pollCreationMessage = window.Store.Msg.get(vote.parentMsgKey).serialize();
window.onPollVote(vote);
});
{ {
const module = window.Store.createOrUpdateReactionsModule; const module = window.Store.createOrUpdateReactionsModule;
const ogMethod = module.createOrUpdateReactions; const ogMethod = module.createOrUpdateReactions;

View File

@@ -6,6 +6,7 @@ const Location = require('./Location');
const Order = require('./Order'); const Order = require('./Order');
const Payment = require('./Payment'); const Payment = require('./Payment');
const { MessageTypes } = require('../util/Constants'); const { MessageTypes } = require('../util/Constants');
const PollVote = require('./PollVote');
/** /**
* Represents a Message on WhatsApp * Represents a Message on WhatsApp
@@ -49,7 +50,7 @@ class Message extends Base {
* Message content * Message content
* @type {string} * @type {string}
*/ */
this.body = this.hasMedia ? data.caption || '' : data.body || ''; this.body = this.hasMedia ? data.caption || '' : data.body || data.pollName || '';
/** /**
* Message type * Message type
@@ -240,6 +241,19 @@ class Message extends Base {
this.selectedRowId = data.listResponse.singleSelectReply.selectedRowId; this.selectedRowId = data.listResponse.singleSelectReply.selectedRowId;
} }
if (this.type == MessageTypes.POLL_CREATION) {
/** Selectable poll options */
this.pollOptions = data.pollOptions.map(option => {
return option.name;
});
/** Current poll votes, refresh with Message.refreshPollVotes() */
this.pollVotes = data.pollVotes.map((pollVote) => {
return new PollVote(this.client, {...pollVote, pollCreationMessage: this});
});
}
return super._patch(data); return super._patch(data);
} }
@@ -527,6 +541,34 @@ class Message extends Base {
} }
return undefined; return undefined;
} }
/**
* Refresh the current poll votes
* @returns {Promise<void>}
*/
async refreshPollVotes() {
if (this.type != MessageTypes.POLL_CREATION) throw 'Invalid usage! Can only be used with a pollCreation message';
const pollVotes = await this.client.evaluate((parentMsgId) => {
return window.Store.PollVote.getForParent(parentMsgId).getModelsArray().map(a => a.serialize());
}, this.id);
this.pollVotes = pollVotes.map((pollVote) => {
return new PollVote(this.client, {...pollVote, pollCreationMessage: this});
});
return;
}
/**
* Vote to the poll.
* @param {Array<string>} selectedOptions Array of options selected.
* @returns {Promise<void>}
*/
async vote(selectedOptions) {
if (this.type != MessageTypes.POLL_CREATION) throw 'Invalid usage! Can only be used with a pollCreation message';
return this.client.evaluate((creationMsgId, selectedOptions) => {
window.WWebJS.votePoll(creationMsgId, selectedOptions);
}, this.id, selectedOptions);
}
} }
module.exports = Message; module.exports = Message;

View File

@@ -0,0 +1,36 @@
'use strict';
const Message = require('./Message');
const Base = require('./Base');
/**
* Represents a Poll Vote on WhatsApp
* @extends {Base}
*/
class PollVote extends Base {
constructor(client, data) {
super(client);
if (data) this._patch(data);
}
_patch(data) {
/** The options selected in this Poll vote */
this.selectedOptions = data.selectedOptionLocalIds.filter(value => value == 1).map((value, selectedOptionLocalId) => {
return data.pollCreationMessage.pollOptions.find(a => a.localId == selectedOptionLocalId).name;
});
/** Sender of the Poll vote */
this.sender = data.sender._serialized;
/** Timestamp of the time it was sent in milliseconds */
this.senderTimestampMs = data.senderTimestampMs;
/** The poll creation message associated with the poll vote */
this.parentPollMessage = new Message(this.client, data.pollCreationMessage);
return super._patch(data);
}
}
module.exports = PollVote;

View File

@@ -52,7 +52,8 @@ exports.Events = {
STATE_CHANGED: 'change_state', STATE_CHANGED: 'change_state',
BATTERY_CHANGED: 'change_battery', BATTERY_CHANGED: 'change_battery',
INCOMING_CALL: 'call', INCOMING_CALL: 'call',
REMOTE_SESSION_SAVED: 'remote_session_saved' REMOTE_SESSION_SAVED: 'remote_session_saved',
POLL_VOTE: 'poll_vote'
}; };
/** /**
@@ -96,6 +97,8 @@ exports.MessageTypes = {
PROTOCOL: 'protocol', PROTOCOL: 'protocol',
REACTION: 'reaction', REACTION: 'reaction',
TEMPLATE_BUTTON_REPLY: 'template_button_reply', TEMPLATE_BUTTON_REPLY: 'template_button_reply',
POLL_CREATION: 'poll_creation',
}; };
/** /**

View File

@@ -6,65 +6,67 @@ exports.ExposeStore = (moduleRaidStr) => {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
window.mR = moduleRaid(); window.mR = moduleRaid();
window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default); window.Store = Object.assign({}, window.mR.findModule(m => m.default && m.default.Chat)[0].default);
window.Store.AppState = window.mR.findModule('Socket')[0].Socket; window.Store.AppState = window.mR.findModule('Socket')[0].Socket;
window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
window.Store.BlockContact = window.mR.findModule('blockContact')[0]; window.Store.BlockContact = window.mR.findModule('blockContact')[0];
window.Store.Call = window.mR.findModule('CallCollection')[0].CallCollection; window.Store.Call = window.mR.findModule('CallCollection')[0].CallCollection;
window.Store.ChatState = window.mR.findModule('sendChatStateComposing')[0];
window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd; window.Store.Cmd = window.mR.findModule('Cmd')[0].Cmd;
window.Store.Conn = window.mR.findModule('Conn')[0].Conn;
window.Store.ConversationMsgs = window.mR.findModule('loadEarlierMsgs')[0];
window.Store.createOrUpdateReactionsModule = window.mR.findModule('createOrUpdateReactions')[0];
window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0]; window.Store.CryptoLib = window.mR.findModule('decryptE2EMedia')[0];
window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager; window.Store.DownloadManager = window.mR.findModule('downloadManager')[0].downloadManager;
window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures;
window.Store.GroupMetadata = window.mR.findModule('GroupMetadata')[0].default.GroupMetadata;
window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0];
window.Store.InviteInfo = window.mR.findModule('sendQueryGroupInvite')[0];
window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection;
window.Store.MediaPrep = window.mR.findModule('MediaPrep')[0];
window.Store.MediaObject = window.mR.findModule('getOrCreateMediaObject')[0];
window.Store.NumberInfo = window.mR.findModule('formattedPhoneNumber')[0];
window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0];
window.Store.MediaUpload = window.mR.findModule('uploadMedia')[0];
window.Store.MsgKey = window.mR.findModule((module) => module.default && module.default.fromString)[0].default;
window.Store.MessageInfo = window.mR.findModule('sendQueryMsgInfo')[0];
window.Store.OpaqueData = window.mR.findModule(module => module.default && module.default.createFromData)[0].default;
window.Store.QueryExist = window.mR.findModule('queryExists')[0].queryExists;
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
window.Store.SendClear = window.mR.findModule('sendClear')[0];
window.Store.SendDelete = window.mR.findModule('sendDelete')[0];
window.Store.SendMessage = window.mR.findModule('addAndSendMsgToChat')[0];
window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
window.Store.User = window.mR.findModule('getMaybeMeUser')[0];
window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
window.Store.UserConstructor = window.mR.findModule((module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null)[0].default;
window.Store.Validators = window.mR.findModule('findLinks')[0];
window.Store.VCard = window.mR.findModule('vcardFromContactModel')[0];
window.Store.WidFactory = window.mR.findModule('createWid')[0];
window.Store.ProfilePic = window.mR.findModule('profilePicResync')[0];
window.Store.PresenceUtils = window.mR.findModule('sendPresenceAvailable')[0];
window.Store.ChatState = window.mR.findModule('sendChatStateComposing')[0];
window.Store.GroupParticipants = window.mR.findModule('sendPromoteParticipants')[0];
window.Store.JoinInviteV4 = window.mR.findModule('sendJoinGroupViaInviteV4')[0];
window.Store.findCommonGroups = window.mR.findModule('findCommonGroups')[0].findCommonGroups;
window.Store.StatusUtils = window.mR.findModule('setMyStatus')[0];
window.Store.ConversationMsgs = window.mR.findModule('loadEarlierMsgs')[0];
window.Store.sendReactionToMsg = window.mR.findModule('sendReactionToMsg')[0].sendReactionToMsg;
window.Store.createOrUpdateReactionsModule = window.mR.findModule('createOrUpdateReactions')[0];
window.Store.EphemeralFields = window.mR.findModule('getEphemeralFields')[0]; window.Store.EphemeralFields = window.mR.findModule('getEphemeralFields')[0];
window.Store.ReplyUtils = window.mR.findModule('canReplyMsg').length > 0 && window.mR.findModule('canReplyMsg')[0]; window.Store.Features = window.mR.findModule('FEATURE_CHANGE_EVENT')[0].LegacyPhoneFeatures;
window.Store.MsgActionChecks = window.mR.findModule('canSenderRevokeMsg')[0]; window.Store.findCommonGroups = window.mR.findModule('findCommonGroups')[0].findCommonGroups;
window.Store.QuotedMsg = window.mR.findModule('getQuotedMsgObj')[0]; window.Store.GroupMetadata = window.mR.findModule('GroupMetadata')[0].default.GroupMetadata;
window.Store.Socket = window.mR.findModule('deprecatedSendIq')[0]; window.Store.GroupParticipants = window.mR.findModule('sendPromoteParticipants')[0];
window.Store.SocketWap = window.mR.findModule('wap')[0];
window.Store.StickerTools = {
...window.mR.findModule('toWebpSticker')[0],
...window.mR.findModule('addWebpMetadata')[0]
};
window.Store.GroupUtils = { window.Store.GroupUtils = {
...window.mR.findModule('sendCreateGroup')[0], ...window.mR.findModule('sendCreateGroup')[0],
...window.mR.findModule('sendSetGroupSubject')[0], ...window.mR.findModule('sendSetGroupSubject')[0],
...window.mR.findModule('markExited')[0] ...window.mR.findModule('markExited')[0]
}; };
window.Store.Invite = window.mR.findModule('sendJoinGroupViaInvite')[0];
window.Store.InviteInfo = window.mR.findModule('sendQueryGroupInvite')[0];
window.Store.JoinInviteV4 = window.mR.findModule('sendJoinGroupViaInviteV4')[0];
window.Store.Label = window.mR.findModule('LabelCollection')[0].LabelCollection;
window.Store.MediaObject = window.mR.findModule('getOrCreateMediaObject')[0];
window.Store.MediaPrep = window.mR.findModule('MediaPrep')[0];
window.Store.MediaTypes = window.mR.findModule('msgToMediaType')[0];
window.Store.MediaUpload = window.mR.findModule('uploadMedia')[0];
window.Store.MessageInfo = window.mR.findModule('sendQueryMsgInfo')[0];
window.Store.MsgActionChecks = window.mR.findModule('canSenderRevokeMsg')[0];
window.Store.MsgKey = window.mR.findModule((module) => module.default && module.default.fromString)[0].default;
window.Store.NumberInfo = window.mR.findModule('formattedPhoneNumber')[0];
window.Store.OpaqueData = window.mR.findModule(module => module.default && module.default.createFromData)[0].default;
window.Store.PresenceUtils = window.mR.findModule('sendPresenceAvailable')[0];
window.Store.ProfilePic = window.mR.findModule('profilePicResync')[0];
window.Store.QueryExist = window.mR.findModule('queryExists')[0].queryExists;
window.Store.QueryOrder = window.mR.findModule('queryOrder')[0];
window.Store.QueryProduct = window.mR.findModule('queryProduct')[0];
window.Store.QuotedMsg = window.mR.findModule('getQuotedMsgObj')[0];
window.Store.ReplyUtils = window.mR.findModule('canReplyMsg').length > 0 && window.mR.findModule('canReplyMsg')[0];
window.Store.SendClear = window.mR.findModule('sendClear')[0];
window.Store.SendDelete = window.mR.findModule('sendDelete')[0];
window.Store.SendMessage = window.mR.findModule('addAndSendMsgToChat')[0];
window.Store.sendReactionToMsg = window.mR.findModule('sendReactionToMsg')[0].sendReactionToMsg;
window.Store.SendSeen = window.mR.findModule('sendSeen')[0];
window.Store.SendVote = window.mR.findModule('sendVote')[0];
window.Store.Socket = window.mR.findModule('deprecatedSendIq')[0];
window.Store.SocketWap = window.mR.findModule('wap')[0];
window.Store.StatusUtils = window.mR.findModule('setMyStatus')[0];
window.Store.StickerTools = {
...window.mR.findModule('toWebpSticker')[0],
...window.mR.findModule('addWebpMetadata')[0]
};
window.Store.UploadUtils = window.mR.findModule((module) => (module.default && module.default.encryptAndUpload) ? module.default : null)[0].default;
window.Store.User = window.mR.findModule('getMaybeMeUser')[0];
window.Store.UserConstructor = window.mR.findModule((module) => (module.default && module.default.prototype && module.default.prototype.isServer && module.default.prototype.isUser) ? module.default : null)[0].default;
window.Store.Validators = window.mR.findModule('findLinks')[0];
window.Store.VCard = window.mR.findModule('vcardFromContactModel')[0];
window.Store.WidFactory = window.mR.findModule('createWid')[0];
if (!window.Store.Chat._find) { if (!window.Store.Chat._find) {
window.Store.Chat._find = e => { window.Store.Chat._find = e => {
@@ -404,6 +406,10 @@ exports.LoadUtils = () => {
msg.id = Object.assign({}, msg.id, { remote: msg.id.remote._serialized }); msg.id = Object.assign({}, msg.id, { remote: msg.id.remote._serialized });
} }
if (msg.type == 'poll_creation') {
msg.pollVotes = window.Store.PollVote.getForParent(msg.id).getModelsArray().map(a => a.serialize());
}
delete msg.pendingAckUpdate; delete msg.pendingAckUpdate;
return msg; return msg;
@@ -621,4 +627,16 @@ exports.LoadUtils = () => {
]); ]);
await window.Store.Socket.deprecatedCastStanza(stanza); await window.Store.Socket.deprecatedCastStanza(stanza);
}; };
window.WWebJS.votePoll = async (pollCreationMessageId, selectedOptions) => {
const msg = window.Store.Msg.get(pollCreationMessageId);
if (msg.type != 'poll_creation') throw 'Quoted message is not a poll creation message!';
let localIdSet = new Set();
msg.pollOptions.map(a => {
for (const option of selectedOptions) {
if (a.name == option) localIdSet.add(a.localId);
}
});
await window.Store.SendVote.sendVote(msg, localIdSet);
};
}; };