Skip to content

Commit

Permalink
feat: Added newsletter functions (close #1365) (#1386)
Browse files Browse the repository at this point in the history
Co-authored-by: Edgard <edgardmessias@gmail.com>
  • Loading branch information
icleitoncosta and edgardmessias committed Oct 8, 2023
1 parent e7e028e commit b0bab71
Show file tree
Hide file tree
Showing 28 changed files with 776 additions and 54 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -86,6 +86,6 @@
"webpack-cli": "^5.1.4"
},
"engines": {
"whatsapp-web": ">=2.2245.8-beta"
"whatsapp-web": ">=2.2321.6-beta"
}
}
9 changes: 7 additions & 2 deletions src/assert/assertChat.ts
Expand Up @@ -16,7 +16,7 @@

import { chat as Chat } from '../';
import { WPPError } from '../util';
import { ChatModel, Wid } from '../whatsapp';
import { ChatModel, NewsletterStore, Wid } from '../whatsapp';

export class InvalidChat extends WPPError {
constructor(readonly id: string | { _serialized: string }) {
Expand All @@ -35,7 +35,12 @@ export async function assertFindChat(id: string | Wid): Promise<ChatModel> {
}

export function assertGetChat(id: string | Wid): ChatModel {
const chat = (Chat as any).get(id);
let chat = null;
if (id.toString().includes('newsletter')) {
chat = NewsletterStore.get(id);
} else {
chat = (Chat as any).get(id);
}

if (!chat) {
throw new InvalidChat(id);
Expand Down
10 changes: 7 additions & 3 deletions src/chat/functions/get.ts
@@ -1,5 +1,5 @@
/*!
* Copyright 2021 WPPConnect Team
* Copyright 2023 WPPConnect Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,7 +15,7 @@
*/

import { assertWid } from '../../assert';
import { ChatModel, ChatStore, Wid } from '../../whatsapp';
import { ChatModel, ChatStore, NewsletterStore, Wid } from '../../whatsapp';

/**
* Find a chat by id
Expand All @@ -24,5 +24,9 @@ import { ChatModel, ChatStore, Wid } from '../../whatsapp';
*/
export function get(chatId: string | Wid): ChatModel | undefined {
const wid = assertWid(chatId);
return ChatStore.get(wid);
if (wid.server === 'newsletter') {
return NewsletterStore.get(wid);
} else {
return ChatStore.get(wid);
}
}
51 changes: 15 additions & 36 deletions src/chat/functions/sendFileMessage.ts
Expand Up @@ -25,9 +25,8 @@ import { wrapModuleFunction } from '../../whatsapp/exportModule';
import {
generateVideoThumbsAndDuration,
isAnimatedWebp,
processRawAudioVideo,
processRawMedia,
processRawSticker,
uploadMedia,
} from '../../whatsapp/functions';
import {
defaultSendMessageOptions,
Expand Down Expand Up @@ -106,10 +105,6 @@ export interface AudioMessageOptions extends FileMessageOptions {
waveform?: boolean;
}

export interface PushToVideoMessageOptions extends FileMessageOptions {
type: 'ptv';
}

export interface DocumentMessageOptions
extends FileMessageOptions,
MessageButtonsOptions {
Expand All @@ -132,6 +127,7 @@ export interface VideoMessageOptions
MessageButtonsOptions {
type: 'video';
isGif?: boolean;
isPtv?: boolean;
}

/**
Expand Down Expand Up @@ -216,7 +212,8 @@ export interface VideoMessageOptions
* '[number]@c.us',
* 'data:application/msword;base64,<a long base64 file...>',
* {
* type: 'ptv',
* type: 'video',
* isPtv: true,
* }
* );
* ```
Expand All @@ -233,7 +230,6 @@ export async function sendFileMessage(
| ImageMessageOptions
| VideoMessageOptions
| StickerMessageOptions
| PushToVideoMessageOptions
): Promise<SendMessageReturn> {
options = {
...defaultSendMessageOptions,
Expand All @@ -258,7 +254,6 @@ export async function sendFileMessage(
isPtt?: boolean;
asDocument?: boolean;
asGif?: boolean;
isPtv?: boolean;
isAudio?: boolean;
asSticker?: boolean;
precomputedFields?: {
Expand All @@ -279,8 +274,6 @@ export async function sendFileMessage(
isViewOnce = options.isViewOnce;
} else if (options.type === 'video') {
rawMediaOptions.asGif = options.isGif;
} else if (options.type === 'ptv') {
rawMediaOptions.isPtv = true;
} else if (options.type === 'document') {
rawMediaOptions.asDocument = true;
} else if (options.type === 'sticker') {
Expand Down Expand Up @@ -309,6 +302,11 @@ export async function sendFileMessage(
}

await mediaPrep.waitForPrep();
if ((options as any)?.isPtv) {
(mediaPrep as any)._mediaData.type = 'ptv';
(mediaPrep as any)._mediaData.fullHeight = 1128;
(mediaPrep as any)._mediaData.fullWidth = 1128;
}

debug(`sending message (${options.type}) with id ${rawMessage.id}`);
const sendMsgResult = mediaPrep.sendToChat(chat, {
Expand Down Expand Up @@ -432,32 +430,13 @@ webpack.onFullReady(() => {
return result;
});

wrapModuleFunction(processRawMedia, async (func, ...args) => {
wrapModuleFunction(uploadMedia, async (func, ...args) => {
const [data] = args;

let result = await func(...args);
if ((args as any)[1]?.isPtv) {
result = await (processRawAudioVideo(
data as any,
false,
null,
false,
null,
data.type(),
true
) as any);
}

return result;
});

wrapModuleFunction(processRawAudioVideo, async (func, ...args) => {
const [data] = args;
const result = await func(...args);

if (data.type() === 'video/mp4' && args[6]) {
result.type = 'ptv';
if ((data as any).mediaType == 'ptv') {
(data as any).mediaType = 'video';
return await func(data);
} else {
return await func(...args);
}
return result;
});
});
35 changes: 33 additions & 2 deletions src/chat/functions/sendRawMessage.ts
Expand Up @@ -17,9 +17,16 @@
import Debug from 'debug';

import { assertFindChat, assertGetChat } from '../../assert';
import { WPPError } from '../../util';
import { MsgModel } from '../../whatsapp';
import { ACK } from '../../whatsapp/enums';
import {
addAndSendMessageEdit,
addAndSendMsgToChat,
addNewsletterMsgsRecords,
msgDataFromMsgModel,
sendNewsletterMessageJob,
updateNewsletterMsgRecord,
} from '../../whatsapp/functions';
import {
defaultSendMessageOptions,
Expand Down Expand Up @@ -60,7 +67,32 @@ export async function sendRawMessage(

debug(`sending message (${rawMessage.type}) with id ${rawMessage.id}`);
let result = null as any;
if (rawMessage.type === 'protocol' && rawMessage.subtype === 'message_edit') {
if (chat?.isNewsletter) {
if (rawMessage.type !== ('chat' || 'image' || 'video'))
throw new WPPError(
'type_not_valid_for_newsletter',
'Please, send a valid type for send message to newsletter. Valdi types: "chat", "image", "video"'
);
const msg = new MsgModel(rawMessage as any);
await addNewsletterMsgsRecords([await msgDataFromMsgModel(msg)]);
const resultNewsletter = await sendNewsletterMessageJob({
msgData: rawMessage,
newsletterJid: chat.id.toString(),
type: rawMessage.type == 'chat' ? 'text' : 'media',
});
chat.msgs.add(msg);

if (resultNewsletter.success) {
msg.t = resultNewsletter.ack.t;
msg.serverId = resultNewsletter.serverId;
}
msg.updateAck(ACK.SENT, true);
await updateNewsletterMsgRecord(msg);
result = [msg, 'OK'];
} else if (
rawMessage.type === 'protocol' &&
rawMessage.subtype === 'message_edit'
) {
const msg = await getMessageById(rawMessage.protocolMessageKey);
await addAndSendMessageEdit(msg, rawMessage);
result = [await getMessageById(rawMessage.protocolMessageKey), null];
Expand All @@ -70,7 +102,6 @@ export async function sendRawMessage(
debug(`message ${rawMessage.id} queued`);

const message = await result[0];

if (options.waitForAck) {
debug(`waiting ack for ${rawMessage.id}`);

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Expand Up @@ -40,6 +40,7 @@ export * as labels from './labels';
export * as profile from './profile';
export * as status from './status';
export * as util from './util';
export * as newsletter from './newsletter';
export * as whatsapp from './whatsapp';
export * as order from './order';

Expand Down
71 changes: 71 additions & 0 deletions src/newsletter/functions/create.ts
@@ -0,0 +1,71 @@
/*!
* Copyright 2023 WPPConnect Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { blobToBase64, convertToFile, downloadImage } from '../../util';
import { createNewsletterQuery } from '../../whatsapp/functions';

export interface ResultCreateNewsletter {
idJid: string;
inviteCode: string;
inviteLink: string;
name: string;
state: string;
subscribersCount: number;
description: string | null;
timestamp: number;
}

/**
* Create a newsletter
*
* @example
* ```javascript
* // To edit name
* WPP.newsletter.create('Name for your newsletter', {
* description: 'Description for that',
* picture: '<base64_string',
* });
* ```
* @category Newsletter
*/
export async function create(
name: string,
opts: { description?: string; picture?: string }
): Promise<ResultCreateNewsletter> {
let pic = undefined;
if (opts?.picture) {
const file = await convertToFile(opts.picture);
pic = await blobToBase64(file);
({ data: pic } = await downloadImage(pic, 'image/jpeg'));
}
const result = await createNewsletterQuery({
name: name,
description: opts?.description || null,
picture: pic || null,
});

return {
idJid: result?.idJid,
inviteCode: result?.newsletterInviteLinkMetadataMixin.inviteCode,
inviteLink: `https://whatsapp.com/channel/${result?.newsletterInviteLinkMetadataMixin.inviteCode}`,
name: result?.newsletterNameMetadataMixin?.nameElementValue,
state: result?.newsletterStateMetadataMixin?.stateType,
subscribersCount:
result?.newsletterSubscribersMetadataMixin.subscribersCount,
description: opts?.description || null,
timestamp: result?.newsletterCreationTimeMetadataMixin?.creationTimeValue,
};
}
41 changes: 41 additions & 0 deletions src/newsletter/functions/destroy.ts
@@ -0,0 +1,41 @@
/*!
* Copyright 2023 WPPConnect Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { WPPError } from '../../util';
import { deleteNewsletter } from '../../whatsapp/functions';

/**
* Delete a newsletter
*
* @example
* ```javascript
* const code = WPP.newsletter.destroy('[newsletter-id]@newsletter');
* ```
*
* @category Newsletter
*/
export async function destroy(id: string): Promise<boolean> {
if (!id || !id.includes('newsletter'))
throw new WPPError(
'send_correctly_newsletter_id',
'Please, send the correct newsletter ID.'
);
try {
return await deleteNewsletter(id);
} catch (error) {
return false;
}
}

0 comments on commit b0bab71

Please sign in to comment.