@omnizap-system/omnizap 2.6.0 → 2.6.2
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 +58 -13
- package/.github/workflows/ci.yml +5 -5
- package/.github/workflows/codeql.yml +1 -1
- package/.github/workflows/db-migration-check.yml +2 -2
- package/.github/workflows/dependency-review.yml +1 -1
- package/.github/workflows/deploy.yml +2 -2
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security-attest-provenance.yml +2 -2
- package/.github/workflows/security-gitleaks.yml +13 -4
- package/.github/workflows/security-runner-hardening.yml +2 -2
- package/.github/workflows/security-scorecard.yml +1 -1
- package/.github/workflows/security-zap-baseline.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +2 -1
- package/.github/workflows/security-zizmor.yml +1 -1
- package/.github/workflows/wiki-sync.yml +1 -1
- package/.gitleaksignore +9 -0
- package/CODE_OF_CONDUCT.md +2 -2
- package/GEMINI.md +64 -0
- package/README.md +52 -82
- package/SECURITY.md +1 -1
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +230 -58
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +145 -4
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +660 -158
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +93 -13
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +858 -15
- package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +135 -27
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +140 -12
- package/app/modules/playModule/playCommand.js +1 -1417
- package/app/modules/playModule/playCommandConstants.js +80 -0
- package/app/modules/playModule/playCommandCore.js +361 -0
- package/app/modules/playModule/playCommandHandlers.js +41 -0
- package/app/modules/playModule/playCommandMediaClient.js +1872 -0
- package/app/modules/playModule/playConfigRuntime.js +245 -4
- package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/quoteModule/quoteCommand.js +3 -2
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/statsModule/rankingCommon.js +5 -4
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/addStickerMetadata.js +4 -3
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerModule/stickerCommand.js +1 -1
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/systemMetricsModule/pingCommand.js +6 -5
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/tiktokCommand.js +2 -1
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/userModule/userCommand.js +72 -23
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/conversationRouterService.js +4 -3
- package/app/services/ai/geminiService.js +132 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/globalModuleAiHelpService.js +3 -2
- package/app/services/ai/messageCommandExecutionService.js +2 -1
- package/app/services/ai/moduleAiHelpCoreService.js +45 -14
- package/app/services/ai/moduleToolExecutorService.js +3 -2
- package/app/services/ai/moduleToolRegistryService.js +2 -1
- package/app/services/ai/toolCandidateSelectorService.js +6 -5
- package/app/services/auth/googleWebLinkService.js +3 -2
- package/app/services/auth/whatsappLoginLinkService.js +3 -2
- package/app/services/external/pokeApiService.js +4 -3
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +57 -26
- package/app/services/infra/featureFlagService.js +2 -1
- package/app/services/messaging/captchaService.js +3 -2
- package/app/services/messaging/newsBroadcastService.js +846 -29
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/services/sticker/stickerFocusService.js +11 -10
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/conversationSessionStore.js +7 -6
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/app/workers/aiLearningWorker.js +6 -5
- package/app/workers/commandConfigEnrichmentWorker.js +4 -3
- package/database/index.js +14 -8
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/docs/wiki/Home.md +1 -1
- package/ecosystem.prod.config.cjs +32 -12
- package/index.js +57 -23
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +20 -6
- package/public/apple-touch-icon.png +0 -0
- package/public/comandos/commands-catalog.json +2853 -3326
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/js/apps/apiDocsApp.js +3 -2
- package/public/js/apps/commandsReactApp.js +280 -99
- package/public/js/apps/createPackApp.js +11 -10
- package/public/js/apps/homeReactApp.js +181 -130
- package/public/js/apps/loginReactApp.js +1 -1
- package/public/js/apps/stickersApp.js +263 -110
- package/public/js/apps/termsReactApp.js +73 -24
- package/public/js/apps/userApp.js +4 -3
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +355 -280
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/api-docs.html +1 -1
- package/public/pages/aup.html +2 -2
- package/public/pages/dpa.html +3 -3
- package/public/pages/licenca.html +4 -4
- package/public/pages/login.html +1 -1
- package/public/pages/notice-and-takedown.html +2 -2
- package/public/pages/politica-de-privacidade.html +6 -6
- package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
- package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
- package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
- package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
- package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
- package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
- package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
- package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
- package/public/pages/stickers-admin.html +1 -1
- package/public/pages/stickers-create.html +1 -1
- package/public/pages/stickers.html +6 -6
- package/public/pages/suboperadores.html +2 -2
- package/public/pages/termos-de-uso-texto-integral.html +6 -6
- package/public/pages/termos-de-uso.html +3 -3
- package/public/pages/user-password-reset.html +4 -5
- package/public/pages/user-systemadm.html +9 -463
- package/public/pages/user.html +2 -2
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +11 -1
- package/scripts/email-broadcast-terms-update.mjs +2 -1
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +166 -2
- package/scripts/generate-module-agents.mjs +2 -1
- package/scripts/generate-seo-satellite-pages.mjs +5 -4
- package/scripts/github-deploy-notify.mjs +2 -1
- package/scripts/github-release-notify.mjs +25 -10
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/release.sh +2 -19
- package/scripts/security-smoketest.mjs +6 -5
- package/scripts/security-web-surface-check.mjs +218 -0
- package/scripts/sticker-catalog-loadtest.mjs +5 -4
- package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
- package/server/auth/jwt/webJwtService.js +1 -1
- package/server/auth/stickerCatalogAuthContext.js +2 -1
- package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
- package/server/auth/userPassword/userPasswordAuthService.js +2 -1
- package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
- package/server/auth/webAccount/webAccountHandlers.js +9 -10
- package/server/controllers/admin/adminPanelHandlers.js +267 -16
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
- package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
- package/server/controllers/sticker/stickerCatalogController.js +23 -36
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/githubController.js +3 -2
- package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/system/systemMetricsController.js +2 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +5 -3
- package/server/http/httpServer.js +11 -6
- package/server/middleware/rateLimit.js +2 -1
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/time/timeModule.js +135 -0
- package/utils/time/timeModule.test.js +65 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +7 -1
- package/public/assets/images/brand-icon-192.png +0 -0
- package/scripts/sync-readme-snapshot.mjs +0 -133
|
@@ -1,36 +1,53 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TABLES, executeQuery, findById, remove, upsert } from '../../database/index.js';
|
|
2
|
+
import { normalizeJid } from '../config/index.js';
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
const AI_PROMPTS_TABLE = TABLES.SYSTEM_AI_PROMPTS;
|
|
5
|
+
const SELECT_AI_PROMPTS_SQL = `SELECT id, prompt FROM \`${AI_PROMPTS_TABLE}\` ORDER BY id ASC`;
|
|
4
6
|
|
|
5
|
-
const
|
|
7
|
+
const normalizePromptJid = (jid) => {
|
|
8
|
+
const raw = String(jid || '').trim();
|
|
9
|
+
if (!raw) return '';
|
|
10
|
+
return normalizeJid(raw) || raw;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const normalizePromptValue = (prompt) => {
|
|
14
|
+
if (typeof prompt === 'string') return prompt;
|
|
15
|
+
if (prompt === null || prompt === undefined) return '';
|
|
16
|
+
return String(prompt);
|
|
17
|
+
};
|
|
6
18
|
|
|
7
19
|
const aiPromptStore = {
|
|
8
20
|
getAllPrompts: async function () {
|
|
9
|
-
const
|
|
10
|
-
|
|
21
|
+
const rows = await executeQuery(SELECT_AI_PROMPTS_SQL);
|
|
22
|
+
const prompts = {};
|
|
23
|
+
for (const row of rows) {
|
|
24
|
+
const promptJid = normalizePromptJid(row?.id);
|
|
25
|
+
if (!promptJid) continue;
|
|
26
|
+
prompts[promptJid] = normalizePromptValue(row?.prompt);
|
|
27
|
+
}
|
|
28
|
+
return prompts;
|
|
11
29
|
},
|
|
12
30
|
|
|
13
31
|
getPrompt: async function (jid) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
32
|
+
const normalizedJid = normalizePromptJid(jid);
|
|
33
|
+
if (!normalizedJid) return null;
|
|
34
|
+
const row = await findById(AI_PROMPTS_TABLE, normalizedJid);
|
|
35
|
+
if (!row) return null;
|
|
36
|
+
return normalizePromptValue(row.prompt);
|
|
17
37
|
},
|
|
18
38
|
|
|
19
39
|
setPrompt: async function (jid, prompt) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
await
|
|
24
|
-
return
|
|
40
|
+
const normalizedJid = normalizePromptJid(jid);
|
|
41
|
+
if (!normalizedJid) return null;
|
|
42
|
+
const normalizedPrompt = normalizePromptValue(prompt);
|
|
43
|
+
await upsert(AI_PROMPTS_TABLE, { id: normalizedJid, prompt: normalizedPrompt });
|
|
44
|
+
return normalizedPrompt;
|
|
25
45
|
},
|
|
26
46
|
|
|
27
47
|
clearPrompt: async function (jid) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
delete prompts[jid];
|
|
32
|
-
await groupConfigStore.updateGroupConfig(PROMPT_CONFIG_ID, { prompts });
|
|
33
|
-
}
|
|
48
|
+
const normalizedJid = normalizePromptJid(jid);
|
|
49
|
+
if (!normalizedJid) return null;
|
|
50
|
+
await remove(AI_PROMPTS_TABLE, normalizedJid);
|
|
34
51
|
return true;
|
|
35
52
|
},
|
|
36
53
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
|
|
1
2
|
const DEFAULT_SESSION_TTL_MS = 15 * 60 * 1000;
|
|
2
3
|
const DEFAULT_HISTORY_LIMIT = 8;
|
|
3
4
|
|
|
@@ -22,7 +23,7 @@ const buildSessionKey = ({ chatId, userId, scope = 'private' } = {}) => {
|
|
|
22
23
|
return `${safeScope}:${safeChatId}:${safeUserId}`;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const pruneExpiredSessions = (nowMs =
|
|
26
|
+
const pruneExpiredSessions = (nowMs = __timeNowMs()) => {
|
|
26
27
|
for (const [key, session] of sessions.entries()) {
|
|
27
28
|
if (!session || !Number.isFinite(session.expiresAt) || session.expiresAt <= nowMs) {
|
|
28
29
|
sessions.delete(key);
|
|
@@ -47,7 +48,7 @@ const getOrCreateSession = ({ chatId, userId, scope = 'private', ttlMs }) => {
|
|
|
47
48
|
const key = buildSessionKey({ chatId, userId, scope });
|
|
48
49
|
if (!key) return null;
|
|
49
50
|
|
|
50
|
-
const nowMs =
|
|
51
|
+
const nowMs = __timeNowMs();
|
|
51
52
|
const safeTtlMs = toFinitePositiveInt(ttlMs, DEFAULT_SESSION_TTL_MS, 1_000);
|
|
52
53
|
const existing = sessions.get(key);
|
|
53
54
|
|
|
@@ -90,7 +91,7 @@ export const appendConversationSessionMessage = ({ chatId, userId, scope = 'priv
|
|
|
90
91
|
role: safeRole,
|
|
91
92
|
text: safeText,
|
|
92
93
|
metadata: metadata && typeof metadata === 'object' ? { ...metadata } : null,
|
|
93
|
-
createdAt:
|
|
94
|
+
createdAt: __timeNowIso(),
|
|
94
95
|
});
|
|
95
96
|
const maxHistory = toFinitePositiveInt(historyLimit, DEFAULT_HISTORY_LIMIT, 1);
|
|
96
97
|
if (session.history.length > maxHistory) {
|
|
@@ -98,7 +99,7 @@ export const appendConversationSessionMessage = ({ chatId, userId, scope = 'priv
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
session.updatedAt =
|
|
102
|
+
session.updatedAt = __timeNowIso();
|
|
102
103
|
return cloneSession(session);
|
|
103
104
|
};
|
|
104
105
|
|
|
@@ -110,10 +111,10 @@ export const setConversationSessionIntent = ({ chatId, userId, scope = 'private'
|
|
|
110
111
|
intent && typeof intent === 'object'
|
|
111
112
|
? {
|
|
112
113
|
...intent,
|
|
113
|
-
updatedAt:
|
|
114
|
+
updatedAt: __timeNowIso(),
|
|
114
115
|
}
|
|
115
116
|
: null;
|
|
116
|
-
session.updatedAt =
|
|
117
|
+
session.updatedAt = __timeNowIso();
|
|
117
118
|
return cloneSession(session);
|
|
118
119
|
};
|
|
119
120
|
|
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
import logger from '#logger';
|
|
2
|
+
import { isGroupJid, normalizeJid } from '../config/index.js';
|
|
2
3
|
import { findById, upsert } from '../../database/index.js';
|
|
3
4
|
|
|
5
|
+
const SYSTEM_CONFIG_PREFIX = 'system:';
|
|
6
|
+
|
|
7
|
+
const normalizeGroupConfigId = (groupId) => {
|
|
8
|
+
const raw = String(groupId || '').trim();
|
|
9
|
+
if (!raw) return '';
|
|
10
|
+
return normalizeJid(raw) || raw;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const isReservedSystemConfigId = (groupId) => groupId.startsWith(SYSTEM_CONFIG_PREFIX);
|
|
14
|
+
|
|
15
|
+
const assertWritableGroupConfigId = (groupId) => {
|
|
16
|
+
if (!groupId) {
|
|
17
|
+
throw new Error('O identificador do grupo é obrigatório para persistir configurações.');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (isReservedSystemConfigId(groupId)) {
|
|
21
|
+
throw new Error(`O id ${groupId} é reservado para configurações de sistema e não pode ser salvo em group_configs.`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!isGroupJid(groupId)) {
|
|
25
|
+
throw new Error(`O id ${groupId} não representa um grupo válido para group_configs.`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
4
29
|
const groupConfigStore = {
|
|
5
30
|
/**
|
|
6
31
|
* Recupera a configuracao de um grupo especifico.
|
|
@@ -8,8 +33,17 @@ const groupConfigStore = {
|
|
|
8
33
|
* @returns {object} A configuracao do grupo, ou um objeto vazio se nao encontrado.
|
|
9
34
|
*/
|
|
10
35
|
getGroupConfig: async function (groupId) {
|
|
36
|
+
const normalizedGroupId = normalizeGroupConfigId(groupId);
|
|
37
|
+
if (!normalizedGroupId || !isGroupJid(normalizedGroupId)) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
if (isReservedSystemConfigId(normalizedGroupId)) {
|
|
41
|
+
logger.warn('Tentativa bloqueada de leitura de configuração reservada em group_configs.', { groupId: normalizedGroupId });
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
|
|
11
45
|
try {
|
|
12
|
-
const record = await findById('group_configs',
|
|
46
|
+
const record = await findById('group_configs', normalizedGroupId);
|
|
13
47
|
if (!record || record.config === null || record.config === undefined) {
|
|
14
48
|
return {};
|
|
15
49
|
}
|
|
@@ -23,7 +57,7 @@ const groupConfigStore = {
|
|
|
23
57
|
} catch (error) {
|
|
24
58
|
logger.error('Error loading group configuration from DB:', {
|
|
25
59
|
error: error.message,
|
|
26
|
-
groupId,
|
|
60
|
+
groupId: normalizedGroupId,
|
|
27
61
|
});
|
|
28
62
|
return {};
|
|
29
63
|
}
|
|
@@ -37,18 +71,20 @@ const groupConfigStore = {
|
|
|
37
71
|
* @param {string} [newConfig.farewellMedia] - Caminho opcional para midia de despedida.
|
|
38
72
|
*/
|
|
39
73
|
updateGroupConfig: async function (groupId, newConfig) {
|
|
40
|
-
const
|
|
74
|
+
const normalizedGroupId = normalizeGroupConfigId(groupId);
|
|
75
|
+
assertWritableGroupConfigId(normalizedGroupId);
|
|
76
|
+
const currentConfig = await this.getGroupConfig(normalizedGroupId);
|
|
41
77
|
const updatedConfig = { ...currentConfig, ...newConfig };
|
|
42
78
|
try {
|
|
43
79
|
await upsert('group_configs', {
|
|
44
|
-
id:
|
|
80
|
+
id: normalizedGroupId,
|
|
45
81
|
config: JSON.stringify(updatedConfig),
|
|
46
82
|
});
|
|
47
83
|
return updatedConfig;
|
|
48
84
|
} catch (error) {
|
|
49
85
|
logger.error('Error updating group configuration in DB:', {
|
|
50
86
|
error: error.message,
|
|
51
|
-
groupId,
|
|
87
|
+
groupId: normalizedGroupId,
|
|
52
88
|
});
|
|
53
89
|
throw error;
|
|
54
90
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TABLES, executeQuery, withTransaction } from '../../database/index.js';
|
|
2
2
|
import { isSameJidUser, normalizeJid } from '../config/index.js';
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const PREMIUM_USERS_TABLE = TABLES.SYSTEM_PREMIUM_USERS;
|
|
5
|
+
const SELECT_PREMIUM_USERS_SQL = `SELECT id FROM \`${PREMIUM_USERS_TABLE}\` ORDER BY id ASC`;
|
|
6
|
+
const DELETE_ALL_PREMIUM_USERS_SQL = `DELETE FROM \`${PREMIUM_USERS_TABLE}\``;
|
|
7
|
+
const INSERT_PREMIUM_USER_SQL = `INSERT INTO \`${PREMIUM_USERS_TABLE}\` (id) VALUES (?)`;
|
|
5
8
|
|
|
6
9
|
const normalizePremiumEntry = (value) => {
|
|
7
10
|
const raw = String(value || '').trim();
|
|
@@ -23,22 +26,33 @@ const normalizeList = (list) => {
|
|
|
23
26
|
return normalizedList;
|
|
24
27
|
};
|
|
25
28
|
|
|
29
|
+
const loadPremiumUsersFromDb = async () => {
|
|
30
|
+
const rows = await executeQuery(SELECT_PREMIUM_USERS_SQL);
|
|
31
|
+
return normalizeList(rows.map((row) => row.id));
|
|
32
|
+
};
|
|
33
|
+
|
|
26
34
|
const premiumUserStore = {
|
|
27
35
|
getPremiumUsers: async function () {
|
|
28
|
-
|
|
29
|
-
return normalizeList(config.premiumUsers);
|
|
36
|
+
return loadPremiumUsersFromDb();
|
|
30
37
|
},
|
|
31
38
|
|
|
32
39
|
setPremiumUsers: async function (premiumUsers) {
|
|
33
40
|
const normalized = normalizeList(premiumUsers);
|
|
34
|
-
|
|
41
|
+
|
|
42
|
+
await withTransaction(async (connection) => {
|
|
43
|
+
await executeQuery(DELETE_ALL_PREMIUM_USERS_SQL, [], connection);
|
|
44
|
+
for (const premiumJid of normalized) {
|
|
45
|
+
await executeQuery(INSERT_PREMIUM_USER_SQL, [premiumJid], connection);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
35
49
|
return normalized;
|
|
36
50
|
},
|
|
37
51
|
|
|
38
52
|
addPremiumUsers: async function (usersToAdd) {
|
|
39
53
|
const current = await this.getPremiumUsers();
|
|
40
54
|
const updated = normalizeList([...current, ...usersToAdd]);
|
|
41
|
-
await
|
|
55
|
+
await this.setPremiumUsers(updated);
|
|
42
56
|
return updated;
|
|
43
57
|
},
|
|
44
58
|
|
|
@@ -46,7 +60,7 @@ const premiumUserStore = {
|
|
|
46
60
|
const current = await this.getPremiumUsers();
|
|
47
61
|
const normalizedTargets = normalizeList(usersToRemove);
|
|
48
62
|
const updated = current.filter((jid) => !normalizedTargets.some((target) => target === jid || isSameJidUser(target, jid)));
|
|
49
|
-
await
|
|
63
|
+
await this.setPremiumUsers(updated);
|
|
50
64
|
return updated;
|
|
51
65
|
},
|
|
52
66
|
};
|