mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Set Status + Set Group Description + Better Message Tags
This commit is contained in:
@@ -74,6 +74,15 @@ export default class WhatsAppWebBase extends WAConnection {
|
|||||||
async getStatus (jid?: string) {
|
async getStatus (jid?: string) {
|
||||||
return this.query(['query', 'Status', jid || this.userMetaData.id]) as Promise<{ status: string }>
|
return this.query(['query', 'Status', jid || this.userMetaData.id]) as Promise<{ status: string }>
|
||||||
}
|
}
|
||||||
|
async setStatus (status: string) {
|
||||||
|
return this.setQuery ([
|
||||||
|
[
|
||||||
|
'status',
|
||||||
|
null,
|
||||||
|
Buffer.from (status, 'utf-8')
|
||||||
|
]
|
||||||
|
])
|
||||||
|
}
|
||||||
/** Get the URL to download the profile picture of a person/group */
|
/** Get the URL to download the profile picture of a person/group */
|
||||||
async getProfilePicture(jid: string | null) {
|
async getProfilePicture(jid: string | null) {
|
||||||
const response = await this.queryExpecting200(['query', 'ProfilePicThumb', jid || this.userMetaData.id])
|
const response = await this.queryExpecting200(['query', 'ProfilePicThumb', jid || this.userMetaData.id])
|
||||||
@@ -204,6 +213,7 @@ export default class WhatsAppWebBase extends WAConnection {
|
|||||||
/** Generic function for action, set queries */
|
/** Generic function for action, set queries */
|
||||||
async setQuery (nodes: WANode[], binaryTags: WATag = [WAMetric.group, WAFlag.ignore], tag?: string) {
|
async setQuery (nodes: WANode[], binaryTags: WATag = [WAMetric.group, WAFlag.ignore], tag?: string) {
|
||||||
const json = ['action', {epoch: this.msgCount.toString(), type: 'set'}, nodes]
|
const json = ['action', {epoch: this.msgCount.toString(), type: 'set'}, nodes]
|
||||||
return this.queryExpecting200(json, binaryTags, null, tag) as Promise<{status: number}>
|
const result = await this.queryExpecting200(json, binaryTags, null, tag) as Promise<{status: number}>
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import WhatsAppWebBase from './Base'
|
import WhatsAppWebBase from './Base'
|
||||||
import { WAMessage, WAMetric, WAFlag, WANode, WAGroupMetadata, WAGroupCreateResponse, WAGroupModification } from '../WAConnection/Constants'
|
import { WAMessage, WAMetric, WAFlag, WANode, WAGroupMetadata, WAGroupCreateResponse, WAGroupModification } from '../WAConnection/Constants'
|
||||||
import { GroupSettingChange } from './Constants'
|
import { GroupSettingChange } from './Constants'
|
||||||
|
import { generateMessageID } from '../WAConnection/Utils'
|
||||||
|
|
||||||
export default class WhatsAppWebGroups extends WhatsAppWebBase {
|
export default class WhatsAppWebGroups extends WhatsAppWebBase {
|
||||||
/** Generic function for group queries */
|
/** Generic function for group queries */
|
||||||
@@ -17,7 +18,8 @@ export default class WhatsAppWebGroups extends WhatsAppWebBase {
|
|||||||
},
|
},
|
||||||
participants ? participants.map(str => ['participant', { jid: str }, null]) : additionalNodes,
|
participants ? participants.map(str => ['participant', { jid: str }, null]) : additionalNodes,
|
||||||
]
|
]
|
||||||
return this.setQuery ([json], [WAMetric.group, WAFlag.ignore], tag)
|
const result = await this.setQuery ([json], [WAMetric.group, WAFlag.ignore], tag)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
/** Get the metadata of the group */
|
/** Get the metadata of the group */
|
||||||
groupMetadata = (jid: string) => this.queryExpecting200(['query', 'GroupMetadata', jid]) as Promise<WAGroupMetadata>
|
groupMetadata = (jid: string) => this.queryExpecting200(['query', 'GroupMetadata', jid]) as Promise<WAGroupMetadata>
|
||||||
@@ -58,6 +60,20 @@ export default class WhatsAppWebGroups extends WhatsAppWebBase {
|
|||||||
*/
|
*/
|
||||||
groupUpdateSubject = (jid: string, title: string) =>
|
groupUpdateSubject = (jid: string, title: string) =>
|
||||||
this.groupQuery('subject', jid, title) as Promise<{ status: number }>
|
this.groupQuery('subject', jid, title) as Promise<{ status: number }>
|
||||||
|
/**
|
||||||
|
* Update the group description
|
||||||
|
* @param {string} jid the ID of the group
|
||||||
|
* @param {string} title the new title of the group
|
||||||
|
*/
|
||||||
|
groupUpdateDescription = async (jid: string, description: string) => {
|
||||||
|
const metadata = await this.groupMetadata (jid)
|
||||||
|
const node: WANode = [
|
||||||
|
'description',
|
||||||
|
{id: generateMessageID(), prev: metadata?.descId},
|
||||||
|
Buffer.from (description, 'utf-8')
|
||||||
|
]
|
||||||
|
return this.groupQuery ('description', jid, null, null, [node])
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Add somebody to the group
|
* Add somebody to the group
|
||||||
* @param jid the ID of the group
|
* @param jid the ID of the group
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
return this.sendGenericMessage(id, m, options)
|
return this.sendGenericMessage(id, m, options)
|
||||||
}
|
}
|
||||||
/** Prepare a media message for sending */
|
/** Prepare a media message for sending */
|
||||||
protected async prepareMediaMessage(buffer: Buffer, mediaType: MessageType, options: MessageOptions = {}) {
|
async prepareMediaMessage(buffer: Buffer, mediaType: MessageType, options: MessageOptions = {}) {
|
||||||
if (mediaType === MessageType.document && !options.mimetype) {
|
if (mediaType === MessageType.document && !options.mimetype) {
|
||||||
throw new Error('mimetype required to send a document')
|
throw new Error('mimetype required to send a document')
|
||||||
}
|
}
|
||||||
@@ -278,10 +278,10 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
const fileSha256 = sha256(buffer)
|
const fileSha256 = sha256(buffer)
|
||||||
// url safe Base64 encode the SHA256 hash of the body
|
// url safe Base64 encode the SHA256 hash of the body
|
||||||
const fileEncSha256B64 = sha256(body)
|
const fileEncSha256B64 = sha256(body)
|
||||||
.toString('base64')
|
.toString('base64')
|
||||||
.replace(/\+/g, '-')
|
.replace(/\+/g, '-')
|
||||||
.replace(/\//g, '_')
|
.replace(/\//g, '_')
|
||||||
.replace(/\=+$/, '')
|
.replace(/\=+$/, '')
|
||||||
|
|
||||||
await generateThumbnail(buffer, mediaType, options)
|
await generateThumbnail(buffer, mediaType, options)
|
||||||
// send a query JSON to obtain the url & auth token to upload our media
|
// send a query JSON to obtain the url & auth token to upload our media
|
||||||
@@ -311,6 +311,7 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
fileLength: buffer.length,
|
fileLength: buffer.length,
|
||||||
fileName: options.filename || 'file',
|
fileName: options.filename || 'file',
|
||||||
gifPlayback: isGIF || null,
|
gifPlayback: isGIF || null,
|
||||||
|
caption: options.caption
|
||||||
}
|
}
|
||||||
return message as WAMessageContent
|
return message as WAMessageContent
|
||||||
}
|
}
|
||||||
@@ -332,13 +333,13 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
message[key].contextInfo.participant = participant
|
message[key].contextInfo.participant = participant
|
||||||
message[key].contextInfo.stanzaId = quoted.key.id
|
message[key].contextInfo.stanzaId = quoted.key.id
|
||||||
message[key].contextInfo.quotedMessage = quoted.message
|
message[key].contextInfo.quotedMessage = quoted.message
|
||||||
|
|
||||||
// if a participant is quoted, then it must be a group
|
// if a participant is quoted, then it must be a group
|
||||||
// hence, remoteJid of group must also be entered
|
// hence, remoteJid of group must also be entered
|
||||||
if (quoted.key.participant) {
|
if (quoted.key.participant) {
|
||||||
message[key].contextInfo.remoteJid = quoted.key.remoteJid
|
message[key].contextInfo.remoteJid = quoted.key.remoteJid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
message[key].caption = options?.caption
|
|
||||||
if (!message[key].jpegThumbnail) message[key].jpegThumbnail = options?.thumbnail
|
if (!message[key].jpegThumbnail) message[key].jpegThumbnail = options?.thumbnail
|
||||||
|
|
||||||
const messageJSON = {
|
const messageJSON = {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import * as assert from 'assert'
|
|||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
import { decodeMediaMessage, validateJIDForSending } from './Utils'
|
import { decodeMediaMessage, validateJIDForSending } from './Utils'
|
||||||
import { promiseTimeout, createTimeout, Browsers } from '../WAConnection/Utils'
|
import { promiseTimeout, createTimeout, Browsers, generateMessageTag } from '../WAConnection/Utils'
|
||||||
|
import { MessageLogLevel } from '../WAConnection/Constants'
|
||||||
|
|
||||||
require ('dotenv').config () // dotenv to load test jid
|
require ('dotenv').config () // dotenv to load test jid
|
||||||
const testJid = process.env.TEST_JID || '1234@s.whatsapp.net' // set TEST_JID=xyz@s.whatsapp.net in a .env file in the root directory
|
const testJid = process.env.TEST_JID || '1234@s.whatsapp.net' // set TEST_JID=xyz@s.whatsapp.net in a .env file in the root directory
|
||||||
@@ -19,6 +20,8 @@ async function sendAndRetreiveMessage(client: WAClient, content, type: MessageTy
|
|||||||
function WAClientTest(name: string, func: (client: WAClient) => void) {
|
function WAClientTest(name: string, func: (client: WAClient) => void) {
|
||||||
describe(name, () => {
|
describe(name, () => {
|
||||||
const client = new WAClient()
|
const client = new WAClient()
|
||||||
|
client.logLevel = MessageLogLevel.info
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const file = './auth_info.json'
|
const file = './auth_info.json'
|
||||||
await client.connectSlim(file)
|
await client.connectSlim(file)
|
||||||
@@ -121,9 +124,24 @@ WAClientTest('Misc', (client) => {
|
|||||||
})
|
})
|
||||||
it('should return the status', async () => {
|
it('should return the status', async () => {
|
||||||
const response = await client.getStatus(testJid)
|
const response = await client.getStatus(testJid)
|
||||||
assert.ok(response.status)
|
|
||||||
assert.strictEqual(typeof response.status, 'string')
|
assert.strictEqual(typeof response.status, 'string')
|
||||||
})
|
})
|
||||||
|
it('should update status', async () => {
|
||||||
|
const newStatus = 'v cool status'
|
||||||
|
|
||||||
|
const response = await client.getStatus()
|
||||||
|
assert.strictEqual(typeof response.status, 'string')
|
||||||
|
|
||||||
|
await createTimeout (1000)
|
||||||
|
|
||||||
|
await client.setStatus (newStatus)
|
||||||
|
const response2 = await client.getStatus()
|
||||||
|
assert.equal (response2.status, newStatus)
|
||||||
|
|
||||||
|
await createTimeout (1000)
|
||||||
|
|
||||||
|
await client.setStatus (response.status) // update back
|
||||||
|
})
|
||||||
it('should return the stories', async () => {
|
it('should return the stories', async () => {
|
||||||
await client.getStories()
|
await client.getStories()
|
||||||
})
|
})
|
||||||
@@ -195,6 +213,15 @@ WAClientTest('Groups', (client) => {
|
|||||||
assert.strictEqual(metadata.id, gid)
|
assert.strictEqual(metadata.id, gid)
|
||||||
assert.strictEqual(metadata.participants.filter((obj) => obj.id.split('@')[0] === testJid.split('@')[0]).length, 1)
|
assert.strictEqual(metadata.participants.filter((obj) => obj.id.split('@')[0] === testJid.split('@')[0]).length, 1)
|
||||||
})
|
})
|
||||||
|
it('should update the group description', async () => {
|
||||||
|
const newDesc = 'Wow this was set from Baileys'
|
||||||
|
|
||||||
|
await client.groupUpdateDescription (gid, newDesc)
|
||||||
|
await createTimeout (1000)
|
||||||
|
|
||||||
|
const metadata = await client.groupMetadata(gid)
|
||||||
|
assert.strictEqual(metadata.desc, newDesc)
|
||||||
|
})
|
||||||
it('should send a message on the group', async () => {
|
it('should send a message on the group', async () => {
|
||||||
await client.sendMessage(gid, 'hello', MessageType.text)
|
await client.sendMessage(gid, 'hello', MessageType.text)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ export default class WAConnectionBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
generateMessageTag () {
|
generateMessageTag () {
|
||||||
return `${this.referenceDate.getTime()/1000}.--${this.msgCount}`
|
return `${Math.round(this.referenceDate.getTime())/1000}.--${this.msgCount}`
|
||||||
}
|
}
|
||||||
protected log(text, level: MessageLogLevel) {
|
protected log(text, level: MessageLogLevel) {
|
||||||
if (this.logLevel >= level)
|
if (this.logLevel >= level)
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export interface WAGroupMetadata {
|
|||||||
creation: number
|
creation: number
|
||||||
desc?: string
|
desc?: string
|
||||||
descOwner?: string
|
descOwner?: string
|
||||||
|
descId?: string
|
||||||
participants: [{ id: string; isAdmin: boolean; isSuperAdmin: boolean }]
|
participants: [{ id: string; isAdmin: boolean; isSuperAdmin: boolean }]
|
||||||
}
|
}
|
||||||
export interface WAGroupModification {
|
export interface WAGroupModification {
|
||||||
|
|||||||
@@ -65,15 +65,23 @@ export function randomBytes(length) {
|
|||||||
return Crypto.randomBytes(length)
|
return Crypto.randomBytes(length)
|
||||||
}
|
}
|
||||||
export const createTimeout = (timeout) => new Promise(resolve => setTimeout(resolve, timeout))
|
export const createTimeout = (timeout) => new Promise(resolve => setTimeout(resolve, timeout))
|
||||||
export function promiseTimeout<T>(ms: number, promise: Promise<T>) {
|
export async function promiseTimeout<T>(ms: number, promise: Promise<T>) {
|
||||||
if (!ms) return promise
|
if (!ms) return promise
|
||||||
// Create a promise that rejects in <ms> milliseconds
|
// Create a promise that rejects in <ms> milliseconds
|
||||||
const timeout = createTimeout (ms).then (() => { throw new BaileysError ('Timed out', promise) })
|
let timeoutI
|
||||||
return Promise.race([promise, timeout]) as Promise<T>
|
const timeout = new Promise(
|
||||||
|
(_, reject) => timeoutI = setTimeout(() => reject(new BaileysError ('Timed out', promise)), ms)
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
const content = await Promise.race([promise, timeout])
|
||||||
|
return content as T
|
||||||
|
} finally {
|
||||||
|
clearTimeout (timeoutI)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// whatsapp requires a message tag for every message, we just use the timestamp as one
|
// whatsapp requires a message tag for every message, we just use the timestamp as one
|
||||||
export function generateMessageTag(epoch?: number) {
|
export function generateMessageTag(epoch?: number) {
|
||||||
let tag = new Date().getTime().toString()
|
let tag = Math.round(new Date().getTime()/1000).toString()
|
||||||
if (epoch) tag += '.--' + epoch // attach epoch if provided
|
if (epoch) tag += '.--' + epoch // attach epoch if provided
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user