Skip to content

Commit

Permalink
feat: Added group management functions
Browse files Browse the repository at this point in the history
  • Loading branch information
edgardmessias committed Oct 2, 2021
1 parent bac71d0 commit decae64
Show file tree
Hide file tree
Showing 11 changed files with 466 additions and 2 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"header/header": [
2,
"block",
Expand Down
259 changes: 259 additions & 0 deletions src/group/Group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/*!
* Copyright 2021 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 Debug from 'debug';
import Emittery from 'emittery';

import { assertGetChat, assertWid } from '../assert';
import { WPPError } from '../util';
import * as webpack from '../webpack';
import { ParticipantModel, Wid } from '../whatsapp';
import {
addParticipants,
demoteParticipants,
promoteParticipants,
removeParticipants,
} from '../whatsapp/functions';
import { ChatEventTypes as GroupEventTypes } from './types';

const debug = Debug('WPP:group');

export class Group extends Emittery<GroupEventTypes> {
constructor() {
super();
webpack.onInjected(() => this.initialize());
}

async initialize() {
debug('initialized');
}

private ensureGroup(groupId: string | Wid) {
const groupChat = assertGetChat(groupId);

if (!groupChat.isGroup) {
throw new WPPError(
'not_a_group',
`Chat ${groupChat.id._serialized} is not a group`
);
}

return groupChat;
}

iAmAdmin(groupId: string | Wid) {
const groupChat = this.ensureGroup(groupId);
return groupChat.groupMetadata!.participants.iAmAdmin();
}

iAmMember(groupId: string | Wid) {
const groupChat = this.ensureGroup(groupId);
return groupChat.groupMetadata!.participants.iAmMember();
}

iAmRestrictedMember(groupId: string | Wid) {
const groupChat = this.ensureGroup(groupId);
return groupChat.groupMetadata!.participants.iAmRestrictedMember();
}

iAmSuperAdmin(groupId: string | Wid) {
const groupChat = this.ensureGroup(groupId);
return groupChat.groupMetadata!.participants.iAmMember();
}

private ensureGroupAndParticipants(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[],
createIfNotExists = false
) {
const groupChat = this.ensureGroup(groupId);

if (!groupChat.groupMetadata!.participants.iAmAdmin()) {
throw new WPPError(
'group_you_are_not_admin',
`You are not admin in ${groupChat.id._serialized}`
);
}

if (!Array.isArray(participantsIds)) {
participantsIds = [participantsIds];
}

const wids = participantsIds.map(assertWid);

const participants = wids.map<ParticipantModel>((wid) => {
let participant = groupChat.groupMetadata?.participants.get(wid);

if (!participant && createIfNotExists) {
participant = new ParticipantModel({
id: wid,
});
}

if (!participant) {
throw new WPPError(
'group_participant_not_found',
`Chat ${groupChat.id._serialized} is not a group`
);
}

return participant;
});

return {
groupChat,
participants,
};
}

canAdd(groupId: string | Wid) {
const groupChat = this.ensureGroup(groupId);
return groupChat.groupMetadata!.participants.canAdd();
}

canDemote(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
) {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds
);

return participants.every((p) =>
groupChat.groupMetadata!.participants.canDemote(p)
);
}

canPromote(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
) {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds
);

return participants.every((p) =>
groupChat.groupMetadata!.participants.canPromote(p)
);
}

canRemove(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
) {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds
);

return participants.every((p) =>
groupChat.groupMetadata!.participants.canRemove(p)
);
}

async addParticipants(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
): Promise<void> {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds,
true
);

if (
participants.some((p) => groupChat.groupMetadata?.participants.get(p.id))
) {
throw new WPPError(
'group_participant_already_a_group_member',
`Group ${groupChat.id._serialized}: Group participant already a group member`
);
}

return addParticipants(groupChat, participants);
}

async removeParticipants(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
): Promise<void> {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds
);

if (
participants.some(
(p) => !groupChat.groupMetadata?.participants.canRemove(p)
)
) {
throw new WPPError(
'group_participant_is_not_a_group_member',
`Group ${groupChat.id._serialized}: Group participant is not a group member`
);
}

return removeParticipants(groupChat, participants);
}

async promoteParticipants(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
): Promise<void> {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds
);

if (
participants.some(
(p) => !groupChat.groupMetadata?.participants.canPromote(p)
)
) {
throw new WPPError(
'group_participant_is_already_a_group_admin',
`Group ${groupChat.id._serialized}: Group participant is already a group admin`
);
}

return promoteParticipants(groupChat, participants);
}

async demoteParticipants(
groupId: string | Wid,
participantsIds: (string | Wid) | (string | Wid)[]
): Promise<void> {
const { groupChat, participants } = this.ensureGroupAndParticipants(
groupId,
participantsIds
);

if (
participants.some(
(p) => !groupChat.groupMetadata?.participants.canDemote(p)
)
) {
throw new WPPError(
'group_participant_is_already_not_a_group_admin',
`Group ${groupChat.id._serialized}: Group participant is already not a group admin`
);
}

return demoteParticipants(groupChat, participants);
}
}
22 changes: 22 additions & 0 deletions src/group/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*!
* Copyright 2021 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 { Group } from './Group';

export * from './Group';
export * from './types';

export default new Group();
63 changes: 63 additions & 0 deletions src/group/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*!
* Copyright 2021 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 { ModelPropertiesContructor, MsgModel } from '../whatsapp';

export interface ChatEventTypes {
change: string;
idle: undefined;
}

export interface GetMessagesOptions {
count?: number;
direction?: 'after' | 'before';
id?: string;
}

export interface SendMessageOptions {
waitForAck?: boolean;
createChat?: boolean;
}

export interface MessageButtonsOptions {
buttons?: Array<{
id: string;
text: string;
}>;
title?: string;
footer?: string;
}

export interface ListMessageOptions extends SendMessageOptions {
buttonText: string;
description: string;
sections: Array<{
title: string;
rows: Array<{
rowId: string;
title: string;
description: string;
}>;
}>;
}

export type TextMessageOptions = SendMessageOptions & MessageButtonsOptions;

export type AllMessageOptions = SendMessageOptions &
MessageButtonsOptions &
Partial<ListMessageOptions>;

export type RawMessage = ModelPropertiesContructor<MsgModel>;
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ import './patch';
import auth from './auth';
import blocklist from './blocklist';
import chat from './chat';
import group from './group';
import status from './status';
import * as webpack from './webpack';

export { auth, blocklist, chat, status, webpack };
export { auth, blocklist, chat, group, status, webpack };

export * as Auth from './auth';
export * as Chat from './chat';
export * as config from './config';
export * as Group from './group';
export * as Status from './status';
export { isInjected, isReady } from './webpack';
export * as whatsapp from './whatsapp';
Expand Down
Loading

0 comments on commit decae64

Please sign in to comment.