@kaikybrofc/omnizap-system 2.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +534 -0
- package/LICENSE +21 -0
- package/README.md +431 -0
- package/RELEASE-v2.1.2.md +83 -0
- package/app/config/adminIdentity.js +87 -0
- package/app/config/baileysConfig.js +693 -0
- package/app/config/groupUtils.js +388 -0
- package/app/connection/socketController.js +992 -0
- package/app/controllers/messageController.js +354 -0
- package/app/modules/adminModule/groupCommandHandlers.js +1294 -0
- package/app/modules/adminModule/groupEventHandlers.js +355 -0
- package/app/modules/aiModule/catCommand.js +1006 -0
- package/app/modules/broadcastModule/noticeCommand.js +416 -0
- package/app/modules/gameModule/diceCommand.js +67 -0
- package/app/modules/menuModule/common.js +311 -0
- package/app/modules/menuModule/menus.js +59 -0
- package/app/modules/playModule/playCommand.js +1615 -0
- package/app/modules/quoteModule/quoteCommand.js +851 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +786 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.js +2082 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +760 -0
- package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
- package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +172 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
- package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
- package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1859 -0
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +6738 -0
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
- package/app/modules/statsModule/globalRankingCommand.js +65 -0
- package/app/modules/statsModule/noMessageCommand.js +288 -0
- package/app/modules/statsModule/rankingCommand.js +60 -0
- package/app/modules/statsModule/rankingCommon.js +889 -0
- package/app/modules/stickerModule/addStickerMetadata.js +239 -0
- package/app/modules/stickerModule/convertToWebp.js +390 -0
- package/app/modules/stickerModule/stickerCommand.js +454 -0
- package/app/modules/stickerModule/stickerConvertCommand.js +156 -0
- package/app/modules/stickerModule/stickerTextCommand.js +657 -0
- package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
- package/app/modules/stickerPackModule/autoPackCollectorService.js +284 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +466 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +88 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +571 -0
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +449 -0
- package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +180 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +4078 -0
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +598 -0
- package/app/modules/stickerPackModule/stickerClassificationService.js +588 -0
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +102 -0
- package/app/modules/stickerPackModule/stickerPackCatalogHttp.js +7506 -0
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1095 -0
- package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +108 -0
- package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +110 -0
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +440 -0
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +337 -0
- package/app/modules/stickerPackModule/stickerPackMessageService.js +296 -0
- package/app/modules/stickerPackModule/stickerPackRepository.js +442 -0
- package/app/modules/stickerPackModule/stickerPackService.js +788 -0
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +51 -0
- package/app/modules/stickerPackModule/stickerPackUtils.js +97 -0
- package/app/modules/stickerPackModule/stickerStorageService.js +507 -0
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +233 -0
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +205 -0
- package/app/modules/systemMetricsModule/pingCommand.js +421 -0
- package/app/modules/tiktokModule/tiktokCommand.js +798 -0
- package/app/modules/userModule/userCommand.js +1217 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +177 -0
- package/app/observability/metrics.js +734 -0
- package/app/services/captchaService.js +492 -0
- package/app/services/dbWriteQueue.js +572 -0
- package/app/services/groupMetadataService.js +279 -0
- package/app/services/lidMapService.js +663 -0
- package/app/services/messagePersistenceService.js +56 -0
- package/app/services/newsBroadcastService.js +351 -0
- package/app/services/pokeApiService.js +398 -0
- package/app/services/queueUtils.js +57 -0
- package/app/services/socketState.js +7 -0
- package/app/store/aiPromptStore.js +38 -0
- package/app/store/groupConfigStore.js +58 -0
- package/app/store/premiumUserStore.js +36 -0
- package/app/utils/antiLink/antiLinkModule.js +804 -0
- package/app/utils/http/getImageBufferModule.js +18 -0
- package/app/utils/json/jsonSanitizer.js +113 -0
- package/app/utils/json/jsonSanitizer.test.js +40 -0
- package/app/utils/logger/loggerModule.js +262 -0
- package/app/utils/systemMetrics/systemMetricsModule.js +91 -0
- package/database/index.js +2052 -0
- package/database/init.js +516 -0
- package/database/migrations/20260203_0001_sticker_packs.sql +54 -0
- package/database/migrations/20260210_0003_rpg_pokemon.sql +58 -0
- package/database/migrations/20260210_0004_rpg_shiny_biome.sql +9 -0
- package/database/migrations/20260210_0005_rpg_missions.sql +14 -0
- package/database/migrations/20260210_0006_rpg_world_pokedex_traits.sql +27 -0
- package/database/migrations/20260210_0007_rpg_raid_pvp.sql +56 -0
- package/database/migrations/20260210_0008_rpg_social_system.sql +195 -0
- package/database/migrations/20260211_0009_rpg_social_xp.sql +36 -0
- package/database/migrations/20260222_0010_remove_message_xp.sql +2 -0
- package/database/migrations/20260226_0011_sticker_asset_classification.sql +17 -0
- package/database/migrations/20260226_0012_sticker_pack_engagement.sql +16 -0
- package/database/migrations/20260226_0013_sticker_marketplace_intelligence.sql +19 -0
- package/database/migrations/20260226_0014_sticker_pack_publish_flow.sql +30 -0
- package/database/migrations/20260226_0014_sticker_worker_queues.sql +42 -0
- package/database/migrations/20260226_0015_sticker_auto_pack_curation_integrity.sql +18 -0
- package/database/migrations/20260226_0016_sticker_web_google_auth_persistence.sql +34 -0
- package/database/migrations/20260226_0017_sticker_web_admin_ban.sql +22 -0
- package/database/migrations/20260226_0018_sticker_web_admin_moderator.sql +18 -0
- package/database/migrations/20260227_0019_sticker_classification_v2_signals.sql +12 -0
- package/database/migrations/20260227_0020_semantic_theme_clusters.sql +35 -0
- package/docker-compose.yml +103 -0
- package/ecosystem.prod.config.cjs +35 -0
- package/eslint.config.js +61 -0
- package/index.js +437 -0
- package/ml/clip_classifier/Dockerfile +16 -0
- package/ml/clip_classifier/README.md +120 -0
- package/ml/clip_classifier/adaptive_scoring.py +40 -0
- package/ml/clip_classifier/classifier.py +654 -0
- package/ml/clip_classifier/embedding_store.py +481 -0
- package/ml/clip_classifier/env_loader.py +15 -0
- package/ml/clip_classifier/llm_label_expander.py +144 -0
- package/ml/clip_classifier/main.py +213 -0
- package/ml/clip_classifier/requirements.txt +10 -0
- package/ml/clip_classifier/similarity_engine.py +74 -0
- package/observability/alert-rules.yml +60 -0
- package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
- package/observability/grafana/dashboards/omnizap-overview.json +170 -0
- package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
- package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
- package/observability/loki-config.yml +38 -0
- package/observability/mysql-exporter.cnf +5 -0
- package/observability/mysql-setup.sql +46 -0
- package/observability/prometheus.yml +32 -0
- package/observability/promtail-config.yml +84 -0
- package/package.json +109 -0
- package/public/api-docs/index.html +144 -0
- package/public/css/github-project-panel.css +297 -0
- package/public/css/stickers-admin.css +1272 -0
- package/public/css/styles.css +671 -0
- package/public/index.html +1311 -0
- package/public/js/apps/apiDocsApp.js +310 -0
- package/public/js/apps/createPackApp.js +2069 -0
- package/public/js/apps/homeApp.js +396 -0
- package/public/js/apps/stickersAdminApp.js +1744 -0
- package/public/js/apps/stickersApp.js +4830 -0
- package/public/js/catalog.js +1019 -0
- package/public/js/github-panel/components/CommitList.js +34 -0
- package/public/js/github-panel/components/ErrorState.js +16 -0
- package/public/js/github-panel/components/GithubProjectPanel.js +106 -0
- package/public/js/github-panel/components/ReleaseList.js +38 -0
- package/public/js/github-panel/components/SkeletonPanel.js +22 -0
- package/public/js/github-panel/components/StatCard.js +15 -0
- package/public/js/github-panel/index.js +15 -0
- package/public/js/github-panel/useGithubRepoData.js +154 -0
- package/public/js/github-panel/vendor/react.js +11 -0
- package/public/js/runtime/react-runtime.js +19 -0
- package/public/licenca/index.html +106 -0
- package/public/stickers/admin/index.html +23 -0
- package/public/stickers/create/index.html +47 -0
- package/public/stickers/index.html +48 -0
- package/public/termos-de-uso/index.html +125 -0
- package/scripts/cache-bust.mjs +107 -0
- package/scripts/deploy.sh +458 -0
- package/scripts/github-deploy-notify.mjs +174 -0
- package/scripts/release.sh +129 -0
|
@@ -0,0 +1,1294 @@
|
|
|
1
|
+
import { handleMenuAdmCommand } from '../menuModule/menus.js';
|
|
2
|
+
import { downloadMediaMessage, getJidServer } from '../../config/baileysConfig.js';
|
|
3
|
+
import { isUserAdmin, createGroup, acceptGroupInvite, getGroupInfo, getGroupRequestParticipantsList, updateGroupAddMode, updateGroupSettings, updateGroupParticipants, leaveGroup, getGroupInviteCode, revokeGroupInviteCode, getGroupInfoFromInvite, updateGroupRequestParticipants, updateGroupSubject, updateGroupDescription, toggleEphemeral } from '../../config/groupUtils.js';
|
|
4
|
+
import groupConfigStore from '../../store/groupConfigStore.js';
|
|
5
|
+
import premiumUserStore from '../../store/premiumUserStore.js';
|
|
6
|
+
import logger from '../../utils/logger/loggerModule.js';
|
|
7
|
+
import { KNOWN_NETWORKS } from '../../utils/antiLink/antiLinkModule.js';
|
|
8
|
+
import { getNewsStatusForGroup, startNewsBroadcastForGroup, stopNewsBroadcastForGroup } from '../../services/newsBroadcastService.js';
|
|
9
|
+
import { sendAndStore } from '../../services/messagePersistenceService.js';
|
|
10
|
+
import { clearCaptchasForGroup } from '../../services/captchaService.js';
|
|
11
|
+
import { getAdminJid, isAdminSenderAsync } from '../../config/adminIdentity.js';
|
|
12
|
+
|
|
13
|
+
const ADMIN_COMMANDS = new Set(['menuadm', 'newgroup', 'add', 'ban', 'up', 'down', 'setsubject', 'setdesc', 'setgroup', 'leave', 'invite', 'revoke', 'join', 'infofrominvite', 'metadata', 'requests', 'updaterequests', 'autorequests', 'temp', 'addmode', 'welcome', 'farewell', 'captcha', 'antilink', 'premium', 'nsfw', 'autosticker', 'noticias', 'news', 'prefix']);
|
|
14
|
+
const OWNER_JID = getAdminJid();
|
|
15
|
+
const DEFAULT_COMMAND_PREFIX = process.env.COMMAND_PREFIX || '/';
|
|
16
|
+
const GROUP_ONLY_COMMAND_MESSAGE = 'Este comando está disponível apenas em conversas de grupo. Execute-o em um grupo para continuar.';
|
|
17
|
+
const NO_PERMISSION_COMMAND_MESSAGE = 'Permissão insuficiente para executar este comando. Solicite suporte a um administrador do grupo.';
|
|
18
|
+
const OWNER_ONLY_COMMAND_MESSAGE = 'Você não possui permissão para executar este comando. Este recurso é exclusivo do administrador principal do bot.';
|
|
19
|
+
|
|
20
|
+
const getParticipantJids = (messageInfo, args) => {
|
|
21
|
+
const mentionedJids = messageInfo.message?.extendedTextMessage?.contextInfo?.mentionedJid || [];
|
|
22
|
+
if (mentionedJids.length > 0) {
|
|
23
|
+
return mentionedJids;
|
|
24
|
+
}
|
|
25
|
+
const repliedTo = messageInfo.message?.extendedTextMessage?.contextInfo?.participant;
|
|
26
|
+
if (repliedTo && args.length === 0) {
|
|
27
|
+
return [repliedTo];
|
|
28
|
+
}
|
|
29
|
+
return args.filter((arg) => getJidServer(arg) === 's.whatsapp.net');
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const isAdminCommand = (command) => ADMIN_COMMANDS.has(command);
|
|
33
|
+
|
|
34
|
+
export async function handleAdminCommand({ command, args, text, sock, messageInfo, remoteJid, senderJid, botJid, isGroupMessage, expirationMessage, commandPrefix = DEFAULT_COMMAND_PREFIX }) {
|
|
35
|
+
if (!isAdminCommand(command)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
switch (command) {
|
|
40
|
+
case 'menuadm': {
|
|
41
|
+
if (!isGroupMessage) {
|
|
42
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
46
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
await handleMenuAdmCommand(sock, remoteJid, messageInfo, expirationMessage, commandPrefix);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
case 'premium': {
|
|
54
|
+
if (!OWNER_JID || !(await isAdminSenderAsync(senderJid))) {
|
|
55
|
+
await sendAndStore(sock, remoteJid, { text: OWNER_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const action = args[0]?.toLowerCase();
|
|
60
|
+
const actionArgs = args.slice(1);
|
|
61
|
+
if (!action || !['add', 'remove', 'list'].includes(action)) {
|
|
62
|
+
await sendAndStore(
|
|
63
|
+
sock,
|
|
64
|
+
remoteJid,
|
|
65
|
+
{
|
|
66
|
+
text: `Formato de uso:
|
|
67
|
+
${commandPrefix}premium <add|remove|list> @usuario1 @usuario2 ...`,
|
|
68
|
+
},
|
|
69
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
70
|
+
);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (action === 'list') {
|
|
75
|
+
const premiumUsers = await premiumUserStore.getPremiumUsers();
|
|
76
|
+
const listText = premiumUsers.length > 0 ? premiumUsers.map((jid) => `• ${jid}`).join('\n') : 'Nenhum usuário premium cadastrado.';
|
|
77
|
+
await sendAndStore(sock, remoteJid, { text: `⭐ *Lista de usuários premium*\n\n${listText}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const participants = getParticipantJids(messageInfo, actionArgs);
|
|
82
|
+
if (participants.length === 0) {
|
|
83
|
+
await sendAndStore(
|
|
84
|
+
sock,
|
|
85
|
+
remoteJid,
|
|
86
|
+
{
|
|
87
|
+
text: `Formato de uso:
|
|
88
|
+
${commandPrefix}premium <add|remove> @usuario1 @usuario2 ...\nTambém é possível responder à mensagem do usuário desejado.`,
|
|
89
|
+
},
|
|
90
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
91
|
+
);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (action === 'add') {
|
|
96
|
+
const updated = await premiumUserStore.addPremiumUsers(participants);
|
|
97
|
+
await sendAndStore(sock, remoteJid, { text: `✅ Usuários adicionados à lista premium com sucesso.\nTotal atual de usuários premium: ${updated.length}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
98
|
+
} else {
|
|
99
|
+
const updated = await premiumUserStore.removePremiumUsers(participants);
|
|
100
|
+
await sendAndStore(sock, remoteJid, { text: `✅ Usuários removidos da lista premium com sucesso.\nTotal atual de usuários premium: ${updated.length}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
case 'nsfw': {
|
|
106
|
+
if (!isGroupMessage) {
|
|
107
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
111
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const action = args[0]?.toLowerCase();
|
|
116
|
+
if (!action || !['on', 'off', 'status'].includes(action)) {
|
|
117
|
+
await sendAndStore(
|
|
118
|
+
sock,
|
|
119
|
+
remoteJid,
|
|
120
|
+
{
|
|
121
|
+
text: `Formato de uso:
|
|
122
|
+
${commandPrefix}nsfw <on|off|status>`,
|
|
123
|
+
},
|
|
124
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
125
|
+
);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (action === 'status') {
|
|
130
|
+
const config = await groupConfigStore.getGroupConfig(remoteJid);
|
|
131
|
+
const enabled = Boolean(config.nsfwEnabled);
|
|
132
|
+
await sendAndStore(sock, remoteJid, { text: `🔞 Status do conteúdo NSFW neste grupo: *${enabled ? 'ativado' : 'desativado'}*.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const enabled = action === 'on';
|
|
137
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { nsfwEnabled: enabled });
|
|
138
|
+
await sendAndStore(sock, remoteJid, { text: `🔞 Configuração NSFW atualizada: *${enabled ? 'ativado' : 'desativado'}* para este grupo.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
case 'autosticker': {
|
|
143
|
+
if (!isGroupMessage) {
|
|
144
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
148
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const action = args[0]?.toLowerCase();
|
|
153
|
+
if (!action || !['on', 'off', 'status'].includes(action)) {
|
|
154
|
+
await sendAndStore(
|
|
155
|
+
sock,
|
|
156
|
+
remoteJid,
|
|
157
|
+
{
|
|
158
|
+
text: `Formato de uso:
|
|
159
|
+
${commandPrefix}autosticker <on|off|status>`,
|
|
160
|
+
},
|
|
161
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
162
|
+
);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (action === 'status') {
|
|
167
|
+
const config = await groupConfigStore.getGroupConfig(remoteJid);
|
|
168
|
+
const enabled = Boolean(config.autoStickerEnabled);
|
|
169
|
+
await sendAndStore(
|
|
170
|
+
sock,
|
|
171
|
+
remoteJid,
|
|
172
|
+
{
|
|
173
|
+
text: `🖼️ Status do AutoSticker neste grupo: *${enabled ? 'ativado' : 'desativado'}*.\n` + 'Quando ativo, imagens e vídeos enviados serão convertidos automaticamente em figurinha.',
|
|
174
|
+
},
|
|
175
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
176
|
+
);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const enabled = action === 'on';
|
|
181
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { autoStickerEnabled: enabled });
|
|
182
|
+
await sendAndStore(
|
|
183
|
+
sock,
|
|
184
|
+
remoteJid,
|
|
185
|
+
{
|
|
186
|
+
text: enabled ? '✅ AutoSticker ativado neste grupo.\nEnvie uma imagem ou vídeo para conversão automática em figurinha.' : '🛑 AutoSticker desativado neste grupo.',
|
|
187
|
+
},
|
|
188
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
189
|
+
);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
case 'newgroup': {
|
|
194
|
+
if (args.length < 2) {
|
|
195
|
+
await sendAndStore(
|
|
196
|
+
sock,
|
|
197
|
+
remoteJid,
|
|
198
|
+
{
|
|
199
|
+
text: `Formato de uso:
|
|
200
|
+
${commandPrefix}newgroup <titulo> <participante1> <participante2> ...`,
|
|
201
|
+
},
|
|
202
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
203
|
+
);
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
const title = args[0];
|
|
207
|
+
const participants = args.slice(1);
|
|
208
|
+
try {
|
|
209
|
+
const group = await createGroup(sock, title, participants);
|
|
210
|
+
await sendAndStore(sock, remoteJid, { text: `O grupo "${group.subject}" foi criado com sucesso.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
211
|
+
} catch (error) {
|
|
212
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível criar o grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
case 'add': {
|
|
218
|
+
if (!isGroupMessage) {
|
|
219
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
223
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const participants = getParticipantJids(messageInfo, args);
|
|
228
|
+
if (participants.length === 0) {
|
|
229
|
+
await sendAndStore(
|
|
230
|
+
sock,
|
|
231
|
+
remoteJid,
|
|
232
|
+
{
|
|
233
|
+
text: `Formato de uso:
|
|
234
|
+
${commandPrefix}add @participante1 @participante2 ...\nTambém é possível informar os JIDs dos participantes.`,
|
|
235
|
+
},
|
|
236
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
237
|
+
);
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
await updateGroupParticipants(sock, remoteJid, participants, 'add');
|
|
242
|
+
await sendAndStore(sock, remoteJid, { text: 'Participantes adicionados com sucesso.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
243
|
+
} catch (error) {
|
|
244
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível adicionar participantes. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
case 'ban': {
|
|
250
|
+
if (!isGroupMessage) {
|
|
251
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
255
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const participants = getParticipantJids(messageInfo, args);
|
|
260
|
+
if (participants.length === 0) {
|
|
261
|
+
await sendAndStore(
|
|
262
|
+
sock,
|
|
263
|
+
remoteJid,
|
|
264
|
+
{
|
|
265
|
+
text: `Formato de uso:
|
|
266
|
+
${commandPrefix}ban @participante1 @participante2 ...\nTambém é possível responder à mensagem do participante desejado.`,
|
|
267
|
+
},
|
|
268
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
269
|
+
);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
if (participants.includes(botJid)) {
|
|
273
|
+
await sendAndStore(sock, remoteJid, { text: 'Operação cancelada: o bot não pode remover a própria conta.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
await updateGroupParticipants(sock, remoteJid, participants, 'remove');
|
|
278
|
+
await sendAndStore(sock, remoteJid, { text: 'Participantes removidos com sucesso.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
279
|
+
const repliedTo = messageInfo.message?.extendedTextMessage?.contextInfo;
|
|
280
|
+
if (repliedTo && participants.includes(repliedTo.participant)) {
|
|
281
|
+
await sendAndStore(sock, remoteJid, {
|
|
282
|
+
delete: messageInfo.message?.extendedTextMessage?.contextInfo?.key,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
} catch (error) {
|
|
286
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível remover participantes. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
287
|
+
}
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
case 'up': {
|
|
292
|
+
if (!isGroupMessage) {
|
|
293
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
297
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const participants = getParticipantJids(messageInfo, args);
|
|
302
|
+
if (participants.length === 0) {
|
|
303
|
+
await sendAndStore(
|
|
304
|
+
sock,
|
|
305
|
+
remoteJid,
|
|
306
|
+
{
|
|
307
|
+
text: `Formato de uso:
|
|
308
|
+
${commandPrefix}up @participante1 @participante2 ...\nTambém é possível informar os JIDs dos participantes.`,
|
|
309
|
+
},
|
|
310
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
311
|
+
);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
if (participants.includes(botJid)) {
|
|
315
|
+
await sendAndStore(sock, remoteJid, { text: 'Operação cancelada: o bot não pode promover a própria conta.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
await updateGroupParticipants(sock, remoteJid, participants, 'promote');
|
|
320
|
+
await sendAndStore(sock, remoteJid, { text: 'Participantes promovidos a administradores com sucesso.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
321
|
+
} catch (error) {
|
|
322
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível promover participantes. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
323
|
+
}
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
case 'down': {
|
|
328
|
+
if (!isGroupMessage) {
|
|
329
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
333
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const participants = getParticipantJids(messageInfo, args);
|
|
338
|
+
if (participants.length === 0) {
|
|
339
|
+
await sendAndStore(
|
|
340
|
+
sock,
|
|
341
|
+
remoteJid,
|
|
342
|
+
{
|
|
343
|
+
text: `Formato de uso:
|
|
344
|
+
${commandPrefix}down @participante1 @participante2 ...\nTambém é possível informar os JIDs dos participantes.`,
|
|
345
|
+
},
|
|
346
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
347
|
+
);
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
if (participants.includes(botJid)) {
|
|
351
|
+
await sendAndStore(sock, remoteJid, { text: 'Operação cancelada: o bot não pode rebaixar a própria conta.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
await updateGroupParticipants(sock, remoteJid, participants, 'demote');
|
|
356
|
+
await sendAndStore(sock, remoteJid, { text: 'Administradores rebaixados para participantes com sucesso.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
357
|
+
} catch (error) {
|
|
358
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível rebaixar administradores. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
case 'setsubject': {
|
|
364
|
+
if (!isGroupMessage) {
|
|
365
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
369
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (args.length < 1) {
|
|
374
|
+
await sendAndStore(
|
|
375
|
+
sock,
|
|
376
|
+
remoteJid,
|
|
377
|
+
{
|
|
378
|
+
text: `Formato de uso:
|
|
379
|
+
${commandPrefix}setsubject <novo_assunto>`,
|
|
380
|
+
},
|
|
381
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
382
|
+
);
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
const newSubject = args.join(' ');
|
|
386
|
+
try {
|
|
387
|
+
await updateGroupSubject(sock, remoteJid, newSubject);
|
|
388
|
+
await sendAndStore(sock, remoteJid, { text: `O assunto do grupo foi atualizado para "${newSubject}" com sucesso.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
389
|
+
} catch (error) {
|
|
390
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível alterar o assunto do grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
391
|
+
}
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
case 'setdesc': {
|
|
396
|
+
if (!isGroupMessage) {
|
|
397
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
401
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (args.length < 1) {
|
|
406
|
+
await sendAndStore(
|
|
407
|
+
sock,
|
|
408
|
+
remoteJid,
|
|
409
|
+
{
|
|
410
|
+
text: `Formato de uso:
|
|
411
|
+
${commandPrefix}setdesc <nova_descricao>`,
|
|
412
|
+
},
|
|
413
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
414
|
+
);
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
const newDescription = args.join(' ');
|
|
418
|
+
try {
|
|
419
|
+
await updateGroupDescription(sock, remoteJid, newDescription);
|
|
420
|
+
await sendAndStore(sock, remoteJid, { text: 'Descrição do grupo atualizada com sucesso.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
421
|
+
} catch (error) {
|
|
422
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível alterar a descrição do grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
423
|
+
}
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
case 'setgroup': {
|
|
428
|
+
if (!isGroupMessage) {
|
|
429
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
433
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (args.length < 1 || !['announcement', 'not_announcement', 'locked', 'unlocked'].includes(args[0])) {
|
|
438
|
+
await sendAndStore(
|
|
439
|
+
sock,
|
|
440
|
+
remoteJid,
|
|
441
|
+
{
|
|
442
|
+
text: `Formato de uso:
|
|
443
|
+
${commandPrefix}setgroup <announcement|not_announcement|locked|unlocked>`,
|
|
444
|
+
},
|
|
445
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
446
|
+
);
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
const setting = args[0];
|
|
450
|
+
try {
|
|
451
|
+
await updateGroupSettings(sock, remoteJid, setting);
|
|
452
|
+
await sendAndStore(sock, remoteJid, { text: `Configuração do grupo atualizada com sucesso para: "${setting}".` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
453
|
+
} catch (error) {
|
|
454
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível alterar a configuração do grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
case 'leave': {
|
|
460
|
+
if (!isGroupMessage) {
|
|
461
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
465
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
await leaveGroup(sock, remoteJid);
|
|
470
|
+
await sendAndStore(sock, remoteJid, { text: 'Saída do grupo concluída com sucesso.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
471
|
+
} catch (error) {
|
|
472
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível sair do grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
473
|
+
}
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
case 'invite': {
|
|
478
|
+
if (!isGroupMessage) {
|
|
479
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
483
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
try {
|
|
488
|
+
const code = await getGroupInviteCode(sock, remoteJid);
|
|
489
|
+
await sendAndStore(
|
|
490
|
+
sock,
|
|
491
|
+
remoteJid,
|
|
492
|
+
{
|
|
493
|
+
text: `Código de convite atual do grupo:
|
|
494
|
+
${code}`,
|
|
495
|
+
},
|
|
496
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
497
|
+
);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível obter o código de convite. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
500
|
+
}
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
case 'revoke': {
|
|
505
|
+
if (!isGroupMessage) {
|
|
506
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
510
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
try {
|
|
515
|
+
const code = await revokeGroupInviteCode(sock, remoteJid);
|
|
516
|
+
await sendAndStore(sock, remoteJid, { text: `Código de convite anterior revogado com sucesso.\nNovo código: ${code}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
517
|
+
} catch (error) {
|
|
518
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível revogar o código de convite. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
519
|
+
}
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
case 'join': {
|
|
524
|
+
if (args.length < 1) {
|
|
525
|
+
await sendAndStore(
|
|
526
|
+
sock,
|
|
527
|
+
remoteJid,
|
|
528
|
+
{
|
|
529
|
+
text: `Formato de uso:
|
|
530
|
+
${commandPrefix}join <codigo_de_convite>`,
|
|
531
|
+
},
|
|
532
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
533
|
+
);
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
const code = args[0];
|
|
537
|
+
try {
|
|
538
|
+
const response = await acceptGroupInvite(sock, code);
|
|
539
|
+
await sendAndStore(sock, remoteJid, { text: `Entrada no grupo concluída com sucesso.\nIdentificador retornado: ${response}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
540
|
+
} catch (error) {
|
|
541
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível entrar no grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
542
|
+
}
|
|
543
|
+
break;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
case 'infofrominvite': {
|
|
547
|
+
if (args.length < 1) {
|
|
548
|
+
await sendAndStore(
|
|
549
|
+
sock,
|
|
550
|
+
remoteJid,
|
|
551
|
+
{
|
|
552
|
+
text: `Formato de uso:
|
|
553
|
+
${commandPrefix}infofrominvite <codigo_de_convite>`,
|
|
554
|
+
},
|
|
555
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
556
|
+
);
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
const code = args[0];
|
|
560
|
+
try {
|
|
561
|
+
const response = await getGroupInfoFromInvite(sock, code);
|
|
562
|
+
await sendAndStore(
|
|
563
|
+
sock,
|
|
564
|
+
remoteJid,
|
|
565
|
+
{
|
|
566
|
+
text: `Informações obtidas pelo convite:
|
|
567
|
+
${JSON.stringify(response, null, 2)}`,
|
|
568
|
+
},
|
|
569
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
570
|
+
);
|
|
571
|
+
} catch (error) {
|
|
572
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível obter informações do grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
573
|
+
}
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
case 'metadata': {
|
|
578
|
+
const groupId = args[0] || remoteJid;
|
|
579
|
+
if (!(await isUserAdmin(groupId, senderJid))) {
|
|
580
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const metadata = getGroupInfo(groupId);
|
|
585
|
+
await sendAndStore(
|
|
586
|
+
sock,
|
|
587
|
+
remoteJid,
|
|
588
|
+
{
|
|
589
|
+
text: `Metadados do grupo:
|
|
590
|
+
${JSON.stringify(metadata, null, 2)}`,
|
|
591
|
+
},
|
|
592
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
593
|
+
);
|
|
594
|
+
} catch (error) {
|
|
595
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível obter metadados do grupo. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
596
|
+
}
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
case 'requests': {
|
|
601
|
+
if (!isGroupMessage) {
|
|
602
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
606
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
try {
|
|
611
|
+
const response = await getGroupRequestParticipantsList(sock, remoteJid);
|
|
612
|
+
await sendAndStore(
|
|
613
|
+
sock,
|
|
614
|
+
remoteJid,
|
|
615
|
+
{
|
|
616
|
+
text: `Solicitações de entrada pendentes:
|
|
617
|
+
${JSON.stringify(response, null, 2)}`,
|
|
618
|
+
},
|
|
619
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
620
|
+
);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível listar solicitações de entrada. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
623
|
+
}
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
case 'updaterequests': {
|
|
628
|
+
if (!isGroupMessage) {
|
|
629
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
630
|
+
break;
|
|
631
|
+
}
|
|
632
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
633
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (args.length < 1 || !['approve', 'reject'].includes(args[0])) {
|
|
638
|
+
await sendAndStore(
|
|
639
|
+
sock,
|
|
640
|
+
remoteJid,
|
|
641
|
+
{
|
|
642
|
+
text: `Formato de uso:
|
|
643
|
+
${commandPrefix}updaterequests <approve|reject> @participante1 ...`,
|
|
644
|
+
},
|
|
645
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
646
|
+
);
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
const action = args[0];
|
|
650
|
+
const participants = getParticipantJids(messageInfo, args.slice(1));
|
|
651
|
+
if (participants.length === 0) {
|
|
652
|
+
await sendAndStore(
|
|
653
|
+
sock,
|
|
654
|
+
remoteJid,
|
|
655
|
+
{
|
|
656
|
+
text: `Formato de uso:
|
|
657
|
+
${commandPrefix}updaterequests <approve|reject> @participante1 ...\nMencione os usuários que devem ser aprovados ou rejeitados.`,
|
|
658
|
+
},
|
|
659
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
660
|
+
);
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
try {
|
|
664
|
+
const response = await updateGroupRequestParticipants(sock, remoteJid, participants, action);
|
|
665
|
+
await sendAndStore(
|
|
666
|
+
sock,
|
|
667
|
+
remoteJid,
|
|
668
|
+
{
|
|
669
|
+
text: `Solicitações de entrada atualizadas com sucesso:
|
|
670
|
+
${JSON.stringify(response, null, 2)}`,
|
|
671
|
+
},
|
|
672
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
673
|
+
);
|
|
674
|
+
} catch (error) {
|
|
675
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível atualizar solicitações de entrada. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
676
|
+
}
|
|
677
|
+
break;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
case 'autorequests': {
|
|
681
|
+
if (!isGroupMessage) {
|
|
682
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
683
|
+
break;
|
|
684
|
+
}
|
|
685
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
686
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const action = args[0]?.toLowerCase();
|
|
691
|
+
if (!action || !['on', 'off', 'status'].includes(action)) {
|
|
692
|
+
await sendAndStore(sock, remoteJid, { text: `Formato de uso:\n${commandPrefix}autorequests <on|off|status>` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (action === 'status') {
|
|
697
|
+
const config = await groupConfigStore.getGroupConfig(remoteJid);
|
|
698
|
+
const enabled = Boolean(config.autoApproveRequestsEnabled);
|
|
699
|
+
await sendAndStore(
|
|
700
|
+
sock,
|
|
701
|
+
remoteJid,
|
|
702
|
+
{
|
|
703
|
+
text: `🤖 Auto-aprovação de solicitações: *${enabled ? 'ativada' : 'desativada'}*.\n` + 'Quando ativo, o bot aprova automaticamente novas solicitações de entrada.',
|
|
704
|
+
},
|
|
705
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
706
|
+
);
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const enabled = action === 'on';
|
|
711
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
712
|
+
autoApproveRequestsEnabled: enabled,
|
|
713
|
+
});
|
|
714
|
+
await sendAndStore(
|
|
715
|
+
sock,
|
|
716
|
+
remoteJid,
|
|
717
|
+
{
|
|
718
|
+
text: enabled ? '✅ Auto-aprovação de solicitações ativada para este grupo.' : '🛑 Auto-aprovação de solicitações desativada para este grupo.',
|
|
719
|
+
},
|
|
720
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
721
|
+
);
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
case 'temp': {
|
|
726
|
+
if (!isGroupMessage) {
|
|
727
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
731
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (args.length < 1) {
|
|
736
|
+
await sendAndStore(
|
|
737
|
+
sock,
|
|
738
|
+
remoteJid,
|
|
739
|
+
{
|
|
740
|
+
text: `Formato de uso:
|
|
741
|
+
${commandPrefix}temp <duracao_em_segundos>`,
|
|
742
|
+
},
|
|
743
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
744
|
+
);
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
const duration = parseInt(args[0]);
|
|
748
|
+
try {
|
|
749
|
+
await toggleEphemeral(sock, remoteJid, duration);
|
|
750
|
+
await sendAndStore(sock, remoteJid, { text: `Configuração de mensagens temporárias atualizada para ${duration} segundos.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
751
|
+
} catch (error) {
|
|
752
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível atualizar mensagens efêmeras. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
753
|
+
}
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
case 'addmode': {
|
|
758
|
+
if (!isGroupMessage) {
|
|
759
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
763
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
if (args.length < 1 || !['all_member_add', 'admin_add'].includes(args[0])) {
|
|
768
|
+
await sendAndStore(
|
|
769
|
+
sock,
|
|
770
|
+
remoteJid,
|
|
771
|
+
{
|
|
772
|
+
text: `Formato de uso:
|
|
773
|
+
${commandPrefix}addmode <all_member_add|admin_add>`,
|
|
774
|
+
},
|
|
775
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
776
|
+
);
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
779
|
+
const mode = args[0];
|
|
780
|
+
try {
|
|
781
|
+
await updateGroupAddMode(sock, remoteJid, mode);
|
|
782
|
+
await sendAndStore(sock, remoteJid, { text: `Modo de adição de membros atualizado com sucesso para: ${mode}.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
783
|
+
} catch (error) {
|
|
784
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível atualizar o modo de adição de membros. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
785
|
+
}
|
|
786
|
+
break;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
case 'prefix': {
|
|
790
|
+
if (!isGroupMessage) {
|
|
791
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
792
|
+
break;
|
|
793
|
+
}
|
|
794
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
795
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const rawPrefix = args[0]?.trim();
|
|
800
|
+
const normalizedKeyword = rawPrefix?.toLowerCase();
|
|
801
|
+
const usageText = ['Formato de uso do comando:', `${commandPrefix}prefix <novo_prefixo>`, `${commandPrefix}prefix status`, `${commandPrefix}prefix reset`].join('\n');
|
|
802
|
+
|
|
803
|
+
if (!rawPrefix) {
|
|
804
|
+
await sendAndStore(sock, remoteJid, { text: usageText }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
if (['status', 'info'].includes(normalizedKeyword)) {
|
|
809
|
+
const config = await groupConfigStore.getGroupConfig(remoteJid);
|
|
810
|
+
const customPrefix = typeof config.commandPrefix === 'string' ? config.commandPrefix.trim() : '';
|
|
811
|
+
const currentPrefix = customPrefix || DEFAULT_COMMAND_PREFIX;
|
|
812
|
+
const isCustom = Boolean(customPrefix && customPrefix !== DEFAULT_COMMAND_PREFIX);
|
|
813
|
+
await sendAndStore(
|
|
814
|
+
sock,
|
|
815
|
+
remoteJid,
|
|
816
|
+
{
|
|
817
|
+
text: [`🔧 Prefixo ativo neste grupo: *${currentPrefix}*`, `Prefixo padrão global: *${DEFAULT_COMMAND_PREFIX}*`, isCustom ? '✅ Este grupo utiliza um prefixo personalizado.' : 'ℹ️ Este grupo utiliza o prefixo padrão.'].join('\n'),
|
|
818
|
+
},
|
|
819
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
820
|
+
);
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (['reset', 'default', 'padrao', 'padrão'].includes(normalizedKeyword)) {
|
|
825
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { commandPrefix: null });
|
|
826
|
+
await sendAndStore(
|
|
827
|
+
sock,
|
|
828
|
+
remoteJid,
|
|
829
|
+
{
|
|
830
|
+
text: `✅ Prefixo restaurado para o padrão global: *${DEFAULT_COMMAND_PREFIX}*`,
|
|
831
|
+
},
|
|
832
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
833
|
+
);
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
if (rawPrefix.length > 5) {
|
|
838
|
+
await sendAndStore(sock, remoteJid, { text: '⚠️ Prefixo inválido: utilize no máximo 5 caracteres.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
if (/\s/.test(rawPrefix)) {
|
|
843
|
+
await sendAndStore(sock, remoteJid, { text: '⚠️ Prefixo inválido: não utilize espaços.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const newPrefix = rawPrefix;
|
|
848
|
+
if (newPrefix === DEFAULT_COMMAND_PREFIX) {
|
|
849
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { commandPrefix: null });
|
|
850
|
+
await sendAndStore(
|
|
851
|
+
sock,
|
|
852
|
+
remoteJid,
|
|
853
|
+
{
|
|
854
|
+
text: `✅ Prefixo atualizado para o padrão global: *${DEFAULT_COMMAND_PREFIX}*`,
|
|
855
|
+
},
|
|
856
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
857
|
+
);
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { commandPrefix: newPrefix });
|
|
862
|
+
await sendAndStore(sock, remoteJid, { text: `✅ Prefixo deste grupo atualizado para: *${newPrefix}*` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
case 'welcome': {
|
|
867
|
+
if (!isGroupMessage) {
|
|
868
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
const subCommandMatch = text.trimStart().match(/^(\S+)([\s\S]*)$/);
|
|
873
|
+
const subCommand = subCommandMatch ? subCommandMatch[1].toLowerCase() : '';
|
|
874
|
+
const messageOrPath = subCommandMatch ? subCommandMatch[2].trimStart() : '';
|
|
875
|
+
|
|
876
|
+
if (!subCommand || !['on', 'off', 'set'].includes(subCommand)) {
|
|
877
|
+
await sendAndStore(
|
|
878
|
+
sock,
|
|
879
|
+
remoteJid,
|
|
880
|
+
{
|
|
881
|
+
text: `Formato de uso:
|
|
882
|
+
${commandPrefix}welcome <on|off|set> [mensagem ou caminho da midia]`,
|
|
883
|
+
},
|
|
884
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
885
|
+
);
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
890
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
try {
|
|
895
|
+
if (subCommand === 'on') {
|
|
896
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { welcomeMessageEnabled: true });
|
|
897
|
+
await sendAndStore(sock, remoteJid, { text: 'Mensagens de boas-vindas ativadas com sucesso para este grupo.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
898
|
+
} else if (subCommand === 'off') {
|
|
899
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { welcomeMessageEnabled: false });
|
|
900
|
+
await sendAndStore(sock, remoteJid, { text: 'Mensagens de boas-vindas desativadas com sucesso para este grupo.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
901
|
+
} else if (subCommand === 'set') {
|
|
902
|
+
if (!messageOrPath && !(messageInfo.message.imageMessage || messageInfo.message.videoMessage)) {
|
|
903
|
+
await sendAndStore(
|
|
904
|
+
sock,
|
|
905
|
+
remoteJid,
|
|
906
|
+
{
|
|
907
|
+
text: `Formato de uso:
|
|
908
|
+
${commandPrefix}welcome set <mensagem ou caminho da midia>\nTambém é possível enviar uma mídia junto ao comando.`,
|
|
909
|
+
},
|
|
910
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
911
|
+
);
|
|
912
|
+
break;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
const quotedMessage = messageInfo.message?.extendedTextMessage?.contextInfo?.quotedMessage;
|
|
916
|
+
let mediaToDownload = null;
|
|
917
|
+
let mediaType = null;
|
|
918
|
+
|
|
919
|
+
if (messageInfo.message.imageMessage) {
|
|
920
|
+
mediaToDownload = messageInfo.message.imageMessage;
|
|
921
|
+
mediaType = 'image';
|
|
922
|
+
} else if (messageInfo.message.videoMessage) {
|
|
923
|
+
mediaToDownload = messageInfo.message.videoMessage;
|
|
924
|
+
mediaType = 'video';
|
|
925
|
+
} else if (quotedMessage) {
|
|
926
|
+
if (quotedMessage.imageMessage) {
|
|
927
|
+
mediaToDownload = quotedMessage.imageMessage;
|
|
928
|
+
mediaType = 'image';
|
|
929
|
+
} else if (quotedMessage.videoMessage) {
|
|
930
|
+
mediaToDownload = quotedMessage.videoMessage;
|
|
931
|
+
mediaType = 'video';
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (mediaToDownload) {
|
|
936
|
+
const downloadedMediaPath = await downloadMediaMessage(mediaToDownload, mediaType, './temp');
|
|
937
|
+
if (downloadedMediaPath) {
|
|
938
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
939
|
+
welcomeMedia: downloadedMediaPath,
|
|
940
|
+
});
|
|
941
|
+
await sendAndStore(sock, remoteJid, { text: `Mídia de boas-vindas configurada com sucesso: ${downloadedMediaPath}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
942
|
+
} else {
|
|
943
|
+
await sendAndStore(sock, remoteJid, { text: 'Não foi possível processar a mídia informada. Tente novamente em instantes.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
944
|
+
}
|
|
945
|
+
} else if (messageOrPath.startsWith('/') || messageOrPath.startsWith('.') || messageOrPath.startsWith('~')) {
|
|
946
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
947
|
+
welcomeMedia: messageOrPath,
|
|
948
|
+
});
|
|
949
|
+
await sendAndStore(sock, remoteJid, { text: `Mídia de boas-vindas configurada com sucesso: ${messageOrPath}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
950
|
+
} else {
|
|
951
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
952
|
+
welcomeMessage: messageOrPath,
|
|
953
|
+
});
|
|
954
|
+
await sendAndStore(sock, remoteJid, { text: `Mensagem de boas-vindas configurada com sucesso: ${messageOrPath}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
} catch (error) {
|
|
958
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível configurar mensagens de boas-vindas. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
959
|
+
}
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
case 'farewell': {
|
|
964
|
+
if (!isGroupMessage) {
|
|
965
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
969
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
const subCommandMatch = text.trimStart().match(/^(\S+)([\s\S]*)$/);
|
|
973
|
+
const subCommand = subCommandMatch ? subCommandMatch[1].toLowerCase() : '';
|
|
974
|
+
const messageOrPath = subCommandMatch ? subCommandMatch[2].trimStart() : '';
|
|
975
|
+
|
|
976
|
+
if (!subCommand || !['on', 'off', 'set'].includes(subCommand)) {
|
|
977
|
+
await sendAndStore(
|
|
978
|
+
sock,
|
|
979
|
+
remoteJid,
|
|
980
|
+
{
|
|
981
|
+
text: `Formato de uso:
|
|
982
|
+
${commandPrefix}farewell <on|off|set> [mensagem ou caminho da midia]`,
|
|
983
|
+
},
|
|
984
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
985
|
+
);
|
|
986
|
+
break;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
try {
|
|
990
|
+
if (subCommand === 'on') {
|
|
991
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { farewellMessageEnabled: true });
|
|
992
|
+
await sendAndStore(sock, remoteJid, { text: 'Mensagens de saída ativadas com sucesso para este grupo.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
993
|
+
} else if (subCommand === 'off') {
|
|
994
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { farewellMessageEnabled: false });
|
|
995
|
+
await sendAndStore(sock, remoteJid, { text: 'Mensagens de saída desativadas com sucesso para este grupo.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
996
|
+
} else if (subCommand === 'set') {
|
|
997
|
+
if (!messageOrPath && !(messageInfo.message.imageMessage || messageInfo.message.videoMessage)) {
|
|
998
|
+
await sendAndStore(
|
|
999
|
+
sock,
|
|
1000
|
+
remoteJid,
|
|
1001
|
+
{
|
|
1002
|
+
text: `Formato de uso:
|
|
1003
|
+
${commandPrefix}farewell set <mensagem ou caminho da midia>\nTambém é possível enviar uma mídia junto ao comando.`,
|
|
1004
|
+
},
|
|
1005
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1006
|
+
);
|
|
1007
|
+
break;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
const quotedMessage = messageInfo.message?.extendedTextMessage?.contextInfo?.quotedMessage;
|
|
1011
|
+
let mediaToDownload = null;
|
|
1012
|
+
let mediaType = null;
|
|
1013
|
+
|
|
1014
|
+
if (messageInfo.message.imageMessage) {
|
|
1015
|
+
mediaToDownload = messageInfo.message.imageMessage;
|
|
1016
|
+
mediaType = 'image';
|
|
1017
|
+
} else if (messageInfo.message.videoMessage) {
|
|
1018
|
+
mediaToDownload = messageInfo.message.videoMessage;
|
|
1019
|
+
mediaType = 'video';
|
|
1020
|
+
} else if (quotedMessage) {
|
|
1021
|
+
if (quotedMessage.imageMessage) {
|
|
1022
|
+
mediaToDownload = quotedMessage.imageMessage;
|
|
1023
|
+
mediaType = 'image';
|
|
1024
|
+
} else if (quotedMessage.videoMessage) {
|
|
1025
|
+
mediaToDownload = quotedMessage.videoMessage;
|
|
1026
|
+
mediaType = 'video';
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if (mediaToDownload) {
|
|
1031
|
+
const downloadedMediaPath = await downloadMediaMessage(mediaToDownload, mediaType, './temp');
|
|
1032
|
+
if (downloadedMediaPath) {
|
|
1033
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
1034
|
+
farewellMedia: downloadedMediaPath,
|
|
1035
|
+
});
|
|
1036
|
+
await sendAndStore(sock, remoteJid, { text: `Mídia de saída configurada com sucesso: ${downloadedMediaPath}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1037
|
+
} else {
|
|
1038
|
+
await sendAndStore(sock, remoteJid, { text: 'Não foi possível processar a mídia informada. Tente novamente em instantes.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1039
|
+
}
|
|
1040
|
+
} else if (messageOrPath.startsWith('/') || messageOrPath.startsWith('.') || messageOrPath.startsWith('~')) {
|
|
1041
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
1042
|
+
farewellMedia: messageOrPath,
|
|
1043
|
+
});
|
|
1044
|
+
await sendAndStore(sock, remoteJid, { text: `Mídia de saída configurada com sucesso: ${messageOrPath}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1045
|
+
} else {
|
|
1046
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
1047
|
+
farewellMessage: messageOrPath,
|
|
1048
|
+
});
|
|
1049
|
+
await sendAndStore(sock, remoteJid, { text: `Mensagem de saída configurada com sucesso: ${messageOrPath}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível configurar mensagens de saída. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1054
|
+
}
|
|
1055
|
+
break;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
case 'captcha': {
|
|
1059
|
+
if (!isGroupMessage) {
|
|
1060
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
1064
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
const action = args[0]?.toLowerCase();
|
|
1069
|
+
if (!action || !['on', 'off', 'status'].includes(action)) {
|
|
1070
|
+
await sendAndStore(sock, remoteJid, { text: `Formato de uso:\n${commandPrefix}captcha <on|off|status>` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1071
|
+
break;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
if (action === 'status') {
|
|
1075
|
+
const config = await groupConfigStore.getGroupConfig(remoteJid);
|
|
1076
|
+
const enabled = Boolean(config.captchaEnabled);
|
|
1077
|
+
await sendAndStore(
|
|
1078
|
+
sock,
|
|
1079
|
+
remoteJid,
|
|
1080
|
+
{
|
|
1081
|
+
text: `🤖 Captcha neste grupo: *${enabled ? 'ativado' : 'desativado'}*.\n` + 'Quando ativo, novos membros precisam reagir ou enviar uma mensagem em até 5 minutos.',
|
|
1082
|
+
},
|
|
1083
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1084
|
+
);
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
const enabled = action === 'on';
|
|
1089
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { captchaEnabled: enabled });
|
|
1090
|
+
if (!enabled) {
|
|
1091
|
+
clearCaptchasForGroup(remoteJid, 'disabled');
|
|
1092
|
+
}
|
|
1093
|
+
await sendAndStore(
|
|
1094
|
+
sock,
|
|
1095
|
+
remoteJid,
|
|
1096
|
+
{
|
|
1097
|
+
text: enabled ? '✅ Captcha ativado. Novos membros terão 5 minutos para reagir ou enviar mensagem.' : '🛑 Captcha desativado para este grupo.',
|
|
1098
|
+
},
|
|
1099
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1100
|
+
);
|
|
1101
|
+
break;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
case 'antilink': {
|
|
1105
|
+
if (!isGroupMessage) {
|
|
1106
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1109
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
1110
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1111
|
+
break;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
const subCommand = args[0] ? args[0].toLowerCase() : '';
|
|
1115
|
+
const currentConfig = await groupConfigStore.getGroupConfig(remoteJid);
|
|
1116
|
+
const allowedNetworks = currentConfig.antilinkAllowedNetworks || [];
|
|
1117
|
+
const allowedDomains = currentConfig.antilinkAllowedDomains || [];
|
|
1118
|
+
const availableNetworks = Object.keys(KNOWN_NETWORKS).sort();
|
|
1119
|
+
|
|
1120
|
+
const parseNetworks = (inputArgs) => {
|
|
1121
|
+
const raw = inputArgs.flatMap((value) => value.split(','));
|
|
1122
|
+
return raw.map((value) => value.trim().toLowerCase()).filter(Boolean);
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
const formatNetworkList = (networks) => (networks.length ? networks.join(', ') : 'nenhuma');
|
|
1126
|
+
|
|
1127
|
+
if (!['on', 'off'].includes(subCommand)) {
|
|
1128
|
+
if (subCommand === 'list') {
|
|
1129
|
+
const status = currentConfig.antilinkEnabled ? 'ativado' : 'desativado';
|
|
1130
|
+
await sendAndStore(
|
|
1131
|
+
sock,
|
|
1132
|
+
remoteJid,
|
|
1133
|
+
{
|
|
1134
|
+
text: `📋 *Antilink - Configuração atual*\n` + `Status: *${status}*\n\n` + `✅ *Redes permitidas*\n${formatNetworkList(allowedNetworks)}\n\n` + `✅ *Domínios permitidos*\n${formatNetworkList(allowedDomains)}\n\n` + `🧭 *Redes disponíveis*\n${availableNetworks.join(', ')}`,
|
|
1135
|
+
},
|
|
1136
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1137
|
+
);
|
|
1138
|
+
break;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
if (subCommand === 'allow' || subCommand === 'disallow') {
|
|
1142
|
+
const requestedNetworks = parseNetworks(args.slice(1));
|
|
1143
|
+
const validNetworks = requestedNetworks.filter((name) => KNOWN_NETWORKS[name]);
|
|
1144
|
+
const invalidNetworks = requestedNetworks.filter((name) => !KNOWN_NETWORKS[name]);
|
|
1145
|
+
|
|
1146
|
+
if (validNetworks.length === 0) {
|
|
1147
|
+
await sendAndStore(
|
|
1148
|
+
sock,
|
|
1149
|
+
remoteJid,
|
|
1150
|
+
{
|
|
1151
|
+
text: `Formato de uso:
|
|
1152
|
+
${commandPrefix}antilink ${subCommand} <rede>\nRedes disponíveis: ${availableNetworks.join(', ')}`,
|
|
1153
|
+
},
|
|
1154
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1155
|
+
);
|
|
1156
|
+
break;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
let updatedNetworks = allowedNetworks;
|
|
1160
|
+
if (subCommand === 'allow') {
|
|
1161
|
+
updatedNetworks = Array.from(new Set([...allowedNetworks, ...validNetworks]));
|
|
1162
|
+
} else {
|
|
1163
|
+
updatedNetworks = allowedNetworks.filter((name) => !validNetworks.includes(name));
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
1167
|
+
antilinkAllowedNetworks: updatedNetworks,
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
const invalidNote = invalidNetworks.length ? `\nIgnorados: ${invalidNetworks.join(', ')}` : '';
|
|
1171
|
+
await sendAndStore(sock, remoteJid, { text: `Redes permitidas atualizadas: ${formatNetworkList(updatedNetworks)}${invalidNote}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1172
|
+
break;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if (subCommand === 'add' || subCommand === 'remove') {
|
|
1176
|
+
const requestedDomains = parseNetworks(args.slice(1));
|
|
1177
|
+
const normalizedDomains = requestedDomains.map((domain) =>
|
|
1178
|
+
domain
|
|
1179
|
+
.replace(/^https?:\/\//, '')
|
|
1180
|
+
.replace(/^www\./, '')
|
|
1181
|
+
.replace(/\/.*$/, ''),
|
|
1182
|
+
);
|
|
1183
|
+
|
|
1184
|
+
if (normalizedDomains.length === 0) {
|
|
1185
|
+
await sendAndStore(
|
|
1186
|
+
sock,
|
|
1187
|
+
remoteJid,
|
|
1188
|
+
{
|
|
1189
|
+
text: `Formato de uso:
|
|
1190
|
+
${commandPrefix}antilink ${subCommand} <dominio>`,
|
|
1191
|
+
},
|
|
1192
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1193
|
+
);
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
let updatedDomains = allowedDomains;
|
|
1198
|
+
if (subCommand === 'add') {
|
|
1199
|
+
updatedDomains = Array.from(new Set([...allowedDomains, ...normalizedDomains]));
|
|
1200
|
+
} else {
|
|
1201
|
+
updatedDomains = allowedDomains.filter((domain) => !normalizedDomains.includes(domain));
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
await groupConfigStore.updateGroupConfig(remoteJid, {
|
|
1205
|
+
antilinkAllowedDomains: updatedDomains,
|
|
1206
|
+
});
|
|
1207
|
+
await sendAndStore(sock, remoteJid, { text: `Domínios permitidos atualizados: ${formatNetworkList(updatedDomains)}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
const status = currentConfig.antilinkEnabled ? 'ativado' : 'desativado';
|
|
1212
|
+
await sendAndStore(
|
|
1213
|
+
sock,
|
|
1214
|
+
remoteJid,
|
|
1215
|
+
{
|
|
1216
|
+
text: `📌 *Guia de uso do Antilink*\n` + `Status atual: *${status}*\n\n` + `✅ *${commandPrefix}antilink on*\nAtiva o bloqueio de links no grupo.\n\n` + `⛔ *${commandPrefix}antilink off*\nDesativa o bloqueio de links no grupo.\n\n` + `📋 *${commandPrefix}antilink list*\nExibe as redes e os domínios permitidos.\n\n` + `➕ *${commandPrefix}antilink allow <rede>*\nPermite uma rede conhecida (ex.: youtube, instagram).\n\n` + `➖ *${commandPrefix}antilink disallow <rede>*\nRemove uma rede conhecida da lista permitida.\n\n` + `🌐 *${commandPrefix}antilink add <dominio>*\nPermite um domínio específico (ex.: exemplo.com).\n\n` + `🗑️ *${commandPrefix}antilink remove <dominio>*\nRemove um domínio específico da lista permitida.\n\n` + `ℹ️ Dica: use *${commandPrefix}antilink list* para consultar as redes disponíveis.`,
|
|
1217
|
+
},
|
|
1218
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1219
|
+
);
|
|
1220
|
+
break;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
try {
|
|
1224
|
+
const isEnabled = subCommand === 'on';
|
|
1225
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { antilinkEnabled: isEnabled });
|
|
1226
|
+
await sendAndStore(sock, remoteJid, { text: `✅ Recurso Antilink ${isEnabled ? 'ativado' : 'desativado'} com sucesso neste grupo.` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1227
|
+
} catch (error) {
|
|
1228
|
+
logger.error('Erro ao configurar o antilink:', {
|
|
1229
|
+
error: error.message,
|
|
1230
|
+
groupId: remoteJid,
|
|
1231
|
+
});
|
|
1232
|
+
await sendAndStore(sock, remoteJid, { text: `Não foi possível configurar o antilink. Detalhes: ${error.message}` }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1233
|
+
}
|
|
1234
|
+
break;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
case 'noticias':
|
|
1238
|
+
case 'news': {
|
|
1239
|
+
if (!isGroupMessage) {
|
|
1240
|
+
await sendAndStore(sock, remoteJid, { text: GROUP_ONLY_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1241
|
+
break;
|
|
1242
|
+
}
|
|
1243
|
+
if (!(await isUserAdmin(remoteJid, senderJid))) {
|
|
1244
|
+
await sendAndStore(sock, remoteJid, { text: NO_PERMISSION_COMMAND_MESSAGE }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1245
|
+
break;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
const action = args[0]?.toLowerCase();
|
|
1249
|
+
if (!action || !['on', 'off', 'status'].includes(action)) {
|
|
1250
|
+
await sendAndStore(
|
|
1251
|
+
sock,
|
|
1252
|
+
remoteJid,
|
|
1253
|
+
{
|
|
1254
|
+
text: `Formato de uso:
|
|
1255
|
+
${commandPrefix}noticias <on|off|status>`,
|
|
1256
|
+
},
|
|
1257
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1258
|
+
);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
if (action === 'status') {
|
|
1263
|
+
const status = await getNewsStatusForGroup(remoteJid);
|
|
1264
|
+
const enabledText = status.enabled ? 'ATIVADO' : 'DESATIVADO';
|
|
1265
|
+
const lastSent = status.lastSentAt ? `\nÚltimo envio: ${status.lastSentAt}` : '';
|
|
1266
|
+
await sendAndStore(
|
|
1267
|
+
sock,
|
|
1268
|
+
remoteJid,
|
|
1269
|
+
{
|
|
1270
|
+
text: `📰 Status de notícias neste grupo: *${enabledText.toLowerCase()}*.\nTotal de envios: ${status.sentCount}.${lastSent}`,
|
|
1271
|
+
},
|
|
1272
|
+
{ quoted: messageInfo, ephemeralExpiration: expirationMessage },
|
|
1273
|
+
);
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
const enableNews = action === 'on';
|
|
1278
|
+
await groupConfigStore.updateGroupConfig(remoteJid, { newsEnabled: enableNews });
|
|
1279
|
+
if (enableNews) {
|
|
1280
|
+
startNewsBroadcastForGroup(remoteJid);
|
|
1281
|
+
await sendAndStore(sock, remoteJid, { text: '📰 Envio automático de notícias ativado. As atualizações serão enviadas com intervalo aproximado de 1 a 2 minutos.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1282
|
+
} else {
|
|
1283
|
+
stopNewsBroadcastForGroup(remoteJid);
|
|
1284
|
+
await sendAndStore(sock, remoteJid, { text: '🛑 Envio automático de notícias desativado para este grupo.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
1285
|
+
}
|
|
1286
|
+
break;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
default:
|
|
1290
|
+
break;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
return true;
|
|
1294
|
+
}
|