Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- CreateIndex
CREATE UNIQUE INDEX `Label_labelId_instanceId_key` ON `Label`(`labelId`, `instanceId`);
2 changes: 2 additions & 0 deletions prisma/mysql-schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ model Label {
updatedAt DateTime @updatedAt @db.Timestamp
Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
instanceId String

@@unique([labelId, instanceId])
}

model Proxy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { Events, wa } from '@api/types/wa.types';
import { AudioConverter, Chatwoot, ConfigService, Database, Openai, S3, WaBusiness } from '@config/env.config';
import { BadRequestException, InternalServerErrorException } from '@exceptions';
import { createJid } from '@utils/createJid';
import { jsonPath } from '@utils/jsonPath';
import { status } from '@utils/renderStatus';
import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios';
Expand Down Expand Up @@ -864,7 +865,7 @@ export class BusinessStartupService extends ChannelStartupService {
where: {
instanceId: this.instanceId,
key: {
path: ['id'],
path: jsonPath('id'),
equals: key.id,
},
},
Expand Down
53 changes: 29 additions & 24 deletions src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import { createId as cuid } from '@paralleldrive/cuid2';
import { Instance, Message } from '@prisma/client';
import { createJid } from '@utils/createJid';
import { fetchLatestWaWebVersion } from '@utils/fetchLatestWaWebVersion';
import { jsonPath } from '@utils/jsonPath';
import { makeProxyAgent, makeProxyAgentUndici } from '@utils/makeProxyAgent';
import { getOnWhatsappCache, saveOnWhatsappCache } from '@utils/onWhatsappCache';
import { status } from '@utils/renderStatus';
Expand Down Expand Up @@ -4184,7 +4185,7 @@ export class BaileysStartupService extends ChannelStartupService {
}

public async getLastMessage(number: string) {
const where: any = { key: { path: ['remoteJid'], equals: number }, instanceId: this.instanceId };
const where: any = { key: { path: jsonPath('remoteJid'), equals: number }, instanceId: this.instanceId };

const messages = await this.prismaRepository.message.findMany({
where,
Expand Down Expand Up @@ -4271,7 +4272,7 @@ export class BaileysStartupService extends ChannelStartupService {
if (messageId) {
const isLogicalDeleted = configService.get<Database>('DATABASE').DELETE_DATA.LOGICAL_MESSAGE_DELETE;
let message = await this.prismaRepository.message.findFirst({
where: { key: { path: ['id'], equals: messageId } },
where: { key: { path: jsonPath('id'), equals: messageId } },
});
if (isLogicalDeleted) {
if (!message) return response;
Expand Down Expand Up @@ -4691,7 +4692,7 @@ export class BaileysStartupService extends ChannelStartupService {
const messageId = messageSent.message?.protocolMessage?.key?.id;
if (messageId && this.configService.get<Database>('DATABASE').SAVE_DATA.NEW_MESSAGE) {
let message = await this.prismaRepository.message.findFirst({
where: { key: { path: ['id'], equals: messageId } },
where: { key: { path: jsonPath('id'), equals: messageId } },
});
if (!message) throw new NotFoundException('Message not found');

Expand Down Expand Up @@ -5329,17 +5330,18 @@ export class BaileysStartupService extends ChannelStartupService {
`INSERT INTO Chat (id, instanceId, remoteJid, labels, createdAt, updatedAt)
VALUES (?, ?, ?, JSON_ARRAY(?), NOW(), NOW())
ON DUPLICATE KEY UPDATE
labels = JSON_ARRAY_APPEND(
COALESCE(labels, JSON_ARRAY()),
'$',
?
labels = IF(
JSON_CONTAINS(COALESCE(labels, JSON_ARRAY()), JSON_QUOTE(?)),
labels,
JSON_ARRAY_APPEND(COALESCE(labels, JSON_ARRAY()), '$', ?)
),
updatedAt = NOW()`,
id,
instanceId,
chatId,
labelId,
labelId,
labelId,
);
} else {
// PostgreSQL version
Expand Down Expand Up @@ -5375,18 +5377,17 @@ export class BaileysStartupService extends ChannelStartupService {
`INSERT INTO Chat (id, instanceId, remoteJid, labels, createdAt, updatedAt)
VALUES (?, ?, ?, JSON_ARRAY(), NOW(), NOW())
ON DUPLICATE KEY UPDATE
labels = COALESCE(
JSON_REMOVE(
labels,
JSON_UNQUOTE(JSON_SEARCH(labels, 'one', ?))
),
JSON_ARRAY()
labels = IF(
JSON_CONTAINS(COALESCE(labels, JSON_ARRAY()), JSON_QUOTE(?)),
JSON_REMOVE(labels, JSON_UNQUOTE(JSON_SEARCH(labels, 'one', ?, '!'))),
COALESCE(labels, JSON_ARRAY())
),
updatedAt = NOW()`,
id,
instanceId,
chatId,
labelId,
labelId.replace(/[!%_]/g, '!$&'),
);
} else {
// PostgreSQL version
Expand Down Expand Up @@ -5622,13 +5623,15 @@ export class BaileysStartupService extends ChannelStartupService {
messageType: query?.where?.messageType,
...timestampFilter,
AND: [
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
keyFilters?.participant ? { key: { path: ['participant'], equals: keyFilters?.participant } } : {},
keyFilters?.id ? { key: { path: jsonPath('id'), equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: jsonPath('fromMe'), equals: keyFilters?.fromMe } } : {},
keyFilters?.participant ? { key: { path: jsonPath('participant'), equals: keyFilters?.participant } } : {},
{
OR: [
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
keyFilters?.remoteJidAlt ? { key: { path: ['remoteJidAlt'], equals: keyFilters?.remoteJidAlt } } : {},
keyFilters?.remoteJid ? { key: { path: jsonPath('remoteJid'), equals: keyFilters?.remoteJid } } : {},
keyFilters?.remoteJidAlt
? { key: { path: jsonPath('remoteJidAlt'), equals: keyFilters?.remoteJidAlt } }
: {},
],
},
],
Expand All @@ -5651,13 +5654,15 @@ export class BaileysStartupService extends ChannelStartupService {
messageType: query?.where?.messageType,
...timestampFilter,
AND: [
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
keyFilters?.participant ? { key: { path: ['participant'], equals: keyFilters?.participant } } : {},
keyFilters?.id ? { key: { path: jsonPath('id'), equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: jsonPath('fromMe'), equals: keyFilters?.fromMe } } : {},
keyFilters?.participant ? { key: { path: jsonPath('participant'), equals: keyFilters?.participant } } : {},
{
OR: [
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
keyFilters?.remoteJidAlt ? { key: { path: ['remoteJidAlt'], equals: keyFilters?.remoteJidAlt } } : {},
keyFilters?.remoteJid ? { key: { path: jsonPath('remoteJid'), equals: keyFilters?.remoteJid } } : {},
keyFilters?.remoteJidAlt
? { key: { path: jsonPath('remoteJidAlt'), equals: keyFilters?.remoteJidAlt } }
: {},
],
},
],
Expand Down Expand Up @@ -5963,7 +5968,7 @@ export class BaileysStartupService extends ChannelStartupService {
const messages = await this.prismaRepository.message.findMany({
where: {
instanceId: this.instanceId,
AND: [{ key: { path: ['remoteJid'], not: null } }],
AND: [{ key: { path: jsonPath('remoteJid'), not: null } }],
},
orderBy: { messageTimestamp: 'desc' },
select: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import ChatwootClient, {
import { request as chatwootRequest } from '@figuro/chatwoot-sdk/dist/core/request';
import { Chatwoot as ChatwootModel, Contact as ContactModel, Message as MessageModel } from '@prisma/client';
import i18next from '@utils/i18n';
import { jsonPath } from '@utils/jsonPath';
import { sendTelemetry } from '@utils/sendTelemetry';
import axios from 'axios';
import { WAMessageContent, WAMessageKey } from 'baileys';
Expand Down Expand Up @@ -1593,7 +1594,7 @@ export class ChatwootService {
const lastMessage = await this.prismaRepository.message.findFirst({
where: {
key: {
path: ['fromMe'],
path: jsonPath('fromMe'),
equals: false,
},
instanceId: instance.instanceId,
Expand Down Expand Up @@ -1623,7 +1624,7 @@ export class ChatwootService {
where: {
instanceId: instance.instanceId,
key: {
path: ['id'],
path: jsonPath('id'),
equals: key.id,
},
},
Expand Down Expand Up @@ -2212,7 +2213,7 @@ export class ChatwootService {
quotedMsg = await this.prismaRepository.message.findFirst({
where: {
key: {
path: ['id'],
path: jsonPath('id'),
equals: quotedId,
},
chatwootMessageId: {
Expand Down Expand Up @@ -2524,7 +2525,7 @@ export class ChatwootService {
await this.prismaRepository.message.deleteMany({
where: {
key: {
path: ['id'],
path: jsonPath('id'),
equals: body.key.id,
},
instanceId: instance.instanceId,
Expand Down Expand Up @@ -2942,7 +2943,7 @@ export class ChatwootService {
where: {
Instance: { name: instance.instanceName },
messageTimestamp: { gte: Number(dayjs().subtract(6, 'hours').unix()) },
AND: ids.map((id) => ({ key: { path: ['id'], not: id } })),
AND: ids.map((id) => ({ key: { path: jsonPath('id'), not: id } })),
},
});

Expand Down
17 changes: 9 additions & 8 deletions src/api/services/channel.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Logger } from '@config/logger.config';
import { NotFoundException } from '@exceptions';
import { Contact, Message, Prisma } from '@prisma/client';
import { createJid } from '@utils/createJid';
import { jsonPath } from '@utils/jsonPath';
import { WASocket } from 'baileys';
import { isArray } from 'class-validator';
import EventEmitter2 from 'eventemitter2';
Expand Down Expand Up @@ -623,10 +624,10 @@ export class ChannelStartupService {
messageType: query?.where?.messageType,
...timestampFilter,
AND: [
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
keyFilters?.participants ? { key: { path: ['participants'], equals: keyFilters?.participants } } : {},
keyFilters?.id ? { key: { path: jsonPath('id'), equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: jsonPath('fromMe'), equals: keyFilters?.fromMe } } : {},
keyFilters?.remoteJid ? { key: { path: jsonPath('remoteJid'), equals: keyFilters?.remoteJid } } : {},
keyFilters?.participants ? { key: { path: jsonPath('participants'), equals: keyFilters?.participants } } : {},
],
},
});
Expand All @@ -647,10 +648,10 @@ export class ChannelStartupService {
messageType: query?.where?.messageType,
...timestampFilter,
AND: [
keyFilters?.id ? { key: { path: ['id'], equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: ['fromMe'], equals: keyFilters?.fromMe } } : {},
keyFilters?.remoteJid ? { key: { path: ['remoteJid'], equals: keyFilters?.remoteJid } } : {},
keyFilters?.participants ? { key: { path: ['participants'], equals: keyFilters?.participants } } : {},
keyFilters?.id ? { key: { path: jsonPath('id'), equals: keyFilters?.id } } : {},
keyFilters?.fromMe ? { key: { path: jsonPath('fromMe'), equals: keyFilters?.fromMe } } : {},
keyFilters?.remoteJid ? { key: { path: jsonPath('remoteJid'), equals: keyFilters?.remoteJid } } : {},
keyFilters?.participants ? { key: { path: jsonPath('participants'), equals: keyFilters?.participants } } : {},
],
},
orderBy: {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/jsonPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { configService, Database } from '@config/env.config';

/**
* Prisma takes the path of a JSON field filter as an array on PostgreSQL (`['id']`)
* but as a JSONPath string on MySQL (`'$.id'`).
*/
export const jsonPath = (field: string): any =>
configService.get<Database>('DATABASE').PROVIDER === 'mysql' ? `$.${field}` : [field];