[core] - Add 'filter.ack' to /messages

This commit is contained in:
devlikepro committed 2025-05-05 13:08:26 +07:00
1 parent 0b044c67bb
commit 640c0d305c
12 files changed
+224 -12

No files matched your search

+2
View File
@@ -31,6 +31,7 @@ import {
GetChatMessagesQuery,
OverviewPaginationParams,
PinMessageRequest,
transformAck,
} from '../structures/chats.dto';
import { EditMessageRequest } from '../structures/chatting.dto';
@@ -100,6 +101,7 @@ class ChatsController {
@WorkingSessionParam session: WhatsappSession,
@Param('chatId') chatId: string,
) {
filter = transformAck(filter);
return session.getChatMessages(chatId, query, filter);
}
+5 -1
View File
@@ -10,7 +10,10 @@ import {
} from '@nestjs/common';
import { ApiOperation, ApiSecurity, ApiTags } from '@nestjs/swagger';
import { WAHAValidationPipe } from '@waha/nestjs/pipes/WAHAValidationPipe';
import { GetChatMessagesFilter } from '@waha/structures/chats.dto';
import {
GetChatMessagesFilter,
transformAck,
} from '@waha/structures/chats.dto';
import { SendButtonsRequest } from '@waha/structures/chatting.buttons.dto';
import { SessionManager } from '../core/abc/manager.abc';
@@ -223,6 +226,7 @@ export class ChattingController {
@Query() query: GetMessageQuery,
@Query() filter: GetChatMessagesFilter,
) {
filter = transformAck(filter);
const whatsapp = await this.manager.getWorkingSession(query.session);
return whatsapp.getChatMessages(query.chatId, query, filter);
}
+50 -1
View File
@@ -3983,9 +3983,10 @@ export namespace messages {
sender?: string;
messageId?: string;
type?: ReceiptType;
messageIds?: string[];
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [6], this.#one_of_decls);
if (!Array.isArray(data) && typeof data == "object") {
if ("session" in data && data.session != undefined) {
this.session = data.session;
@@ -4002,6 +4003,9 @@ export namespace messages {
if ("type" in data && data.type != undefined) {
this.type = data.type;
}
if ("messageIds" in data && data.messageIds != undefined) {
this.messageIds = data.messageIds;
}
}
}
get session() {
@@ -4037,12 +4041,19 @@ export namespace messages {
set type(value: ReceiptType) {
pb_1.Message.setField(this, 5, value);
}
get messageIds() {
return pb_1.Message.getFieldWithDefault(this, 6, []) as string[];
}
set messageIds(value: string[]) {
pb_1.Message.setField(this, 6, value);
}
static fromObject(data: {
session?: ReturnType<typeof Session.prototype.toObject>;
jid?: string;
sender?: string;
messageId?: string;
type?: ReceiptType;
messageIds?: string[];
}): MarkReadRequest {
const message = new MarkReadRequest({});
if (data.session != null) {
@@ -4060,6 +4071,9 @@ export namespace messages {
if (data.type != null) {
message.type = data.type;
}
if (data.messageIds != null) {
message.messageIds = data.messageIds;
}
return message;
}
toObject() {
@@ -4069,6 +4083,7 @@ export namespace messages {
sender?: string;
messageId?: string;
type?: ReceiptType;
messageIds?: string[];
} = {};
if (this.session != null) {
data.session = this.session.toObject();
@@ -4085,6 +4100,9 @@ export namespace messages {
if (this.type != null) {
data.type = this.type;
}
if (this.messageIds != null) {
data.messageIds = this.messageIds;
}
return data;
}
serialize(): Uint8Array;
@@ -4101,6 +4119,8 @@ export namespace messages {
writer.writeString(4, this.messageId);
if (this.type != ReceiptType.READ)
writer.writeEnum(5, this.type);
if (this.messageIds.length)
writer.writeRepeatedString(6, this.messageIds);
if (!w)
return writer.getResultBuffer();
}
@@ -4125,6 +4145,9 @@ export namespace messages {
case 5:
message.type = reader.readEnum();
break;
case 6:
pb_1.Message.addToRepeatedField(message, 6, reader.readString());
break;
default: reader.skipField();
}
}
@@ -6934,6 +6957,7 @@ export namespace messages {
timestampGte?: OptionalUInt64;
timestampLte?: OptionalUInt64;
fromMe?: OptionalBool;
status?: OptionalUInt32;
}) {
super();
pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls);
@@ -6950,6 +6974,9 @@ export namespace messages {
if ("fromMe" in data && data.fromMe != undefined) {
this.fromMe = data.fromMe;
}
if ("status" in data && data.status != undefined) {
this.status = data.status;
}
}
}
get jid() {
@@ -6988,11 +7015,21 @@ export namespace messages {
get has_fromMe() {
return pb_1.Message.getField(this, 4) != null;
}
get status() {
return pb_1.Message.getWrapperField(this, OptionalUInt32, 5) as OptionalUInt32;
}
set status(value: OptionalUInt32) {
pb_1.Message.setWrapperField(this, 5, value);
}
get has_status() {
return pb_1.Message.getField(this, 5) != null;
}
static fromObject(data: {
jid?: ReturnType<typeof OptionalString.prototype.toObject>;
timestampGte?: ReturnType<typeof OptionalUInt64.prototype.toObject>;
timestampLte?: ReturnType<typeof OptionalUInt64.prototype.toObject>;
fromMe?: ReturnType<typeof OptionalBool.prototype.toObject>;
status?: ReturnType<typeof OptionalUInt32.prototype.toObject>;
}): MessageFilters {
const message = new MessageFilters({});
if (data.jid != null) {
@@ -7007,6 +7044,9 @@ export namespace messages {
if (data.fromMe != null) {
message.fromMe = OptionalBool.fromObject(data.fromMe);
}
if (data.status != null) {
message.status = OptionalUInt32.fromObject(data.status);
}
return message;
}
toObject() {
@@ -7015,6 +7055,7 @@ export namespace messages {
timestampGte?: ReturnType<typeof OptionalUInt64.prototype.toObject>;
timestampLte?: ReturnType<typeof OptionalUInt64.prototype.toObject>;
fromMe?: ReturnType<typeof OptionalBool.prototype.toObject>;
status?: ReturnType<typeof OptionalUInt32.prototype.toObject>;
} = {};
if (this.jid != null) {
data.jid = this.jid.toObject();
@@ -7028,6 +7069,9 @@ export namespace messages {
if (this.fromMe != null) {
data.fromMe = this.fromMe.toObject();
}
if (this.status != null) {
data.status = this.status.toObject();
}
return data;
}
serialize(): Uint8Array;
@@ -7042,6 +7086,8 @@ export namespace messages {
writer.writeMessage(3, this.timestampLte, () => this.timestampLte.serialize(writer));
if (this.has_fromMe)
writer.writeMessage(4, this.fromMe, () => this.fromMe.serialize(writer));
if (this.has_status)
writer.writeMessage(5, this.status, () => this.status.serialize(writer));
if (!w)
return writer.getResultBuffer();
}
@@ -7063,6 +7109,9 @@ export namespace messages {
case 4:
reader.readMessage(message.fromMe, () => message.fromMe = OptionalBool.deserialize(reader));
break;
case 5:
reader.readMessage(message.status, () => message.status = OptionalUInt32.deserialize(reader));
break;
default: reader.skipField();
}
}
+110 -3
View File
@@ -905,7 +905,7 @@ if (goog.DEBUG && !COMPILED) {
* @constructor
*/
proto.messages.MarkReadRequest = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
jspb.Message.initialize(this, opt_data, 0, -1, proto.messages.MarkReadRequest.repeatedFields_, null);
};
goog.inherits(proto.messages.MarkReadRequest, jspb.Message);
if (goog.DEBUG && !COMPILED) {
@@ -8962,6 +8962,13 @@ proto.messages.SubscribePresenceRequest.prototype.setJid = function(value) {
/**
* List of repeated fields within this message type.
* @private {!Array<number>}
* @const
*/
proto.messages.MarkReadRequest.repeatedFields_ = [6];
if (jspb.Message.GENERATE_TO_OBJECT) {
@@ -8997,7 +9004,8 @@ proto.messages.MarkReadRequest.toObject = function(includeInstance, msg) {
jid: jspb.Message.getFieldWithDefault(msg, 2, ""),
sender: jspb.Message.getFieldWithDefault(msg, 3, ""),
messageid: jspb.Message.getFieldWithDefault(msg, 4, ""),
type: jspb.Message.getFieldWithDefault(msg, 5, 0)
type: jspb.Message.getFieldWithDefault(msg, 5, 0),
messageidsList: (f = jspb.Message.getRepeatedField(msg, 6)) == null ? undefined : f
};
if (includeInstance) {
@@ -9055,6 +9063,10 @@ proto.messages.MarkReadRequest.deserializeBinaryFromReader = function(msg, reade
var value = /** @type {!proto.messages.ReceiptType} */ (reader.readEnum());
msg.setType(value);
break;
case 6:
var value = /** @type {string} */ (reader.readString());
msg.addMessageids(value);
break;
default:
reader.skipField();
break;
@@ -9120,6 +9132,13 @@ proto.messages.MarkReadRequest.serializeBinaryToWriter = function(message, write
f
);
}
f = message.getMessageidsList();
if (f.length > 0) {
writer.writeRepeatedString(
6,
f
);
}
};
@@ -9232,6 +9251,43 @@ proto.messages.MarkReadRequest.prototype.setType = function(value) {
};
/**
* repeated string messageIds = 6;
* @return {!Array<string>}
*/
proto.messages.MarkReadRequest.prototype.getMessageidsList = function() {
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 6));
};
/**
* @param {!Array<string>} value
* @return {!proto.messages.MarkReadRequest} returns this
*/
proto.messages.MarkReadRequest.prototype.setMessageidsList = function(value) {
return jspb.Message.setField(this, 6, value || []);
};
/**
* @param {string} value
* @param {number=} opt_index
* @return {!proto.messages.MarkReadRequest} returns this
*/
proto.messages.MarkReadRequest.prototype.addMessageids = function(value, opt_index) {
return jspb.Message.addToRepeatedField(this, 6, value, opt_index);
};
/**
* Clears the list making it empty but non-null.
* @return {!proto.messages.MarkReadRequest} returns this
*/
proto.messages.MarkReadRequest.prototype.clearMessageidsList = function() {
return this.setMessageidsList([]);
};
/**
* List of repeated fields within this message type.
@@ -14523,7 +14579,8 @@ proto.messages.MessageFilters.toObject = function(includeInstance, msg) {
jid: (f = msg.getJid()) && proto.messages.OptionalString.toObject(includeInstance, f),
timestampgte: (f = msg.getTimestampgte()) && proto.messages.OptionalUInt64.toObject(includeInstance, f),
timestamplte: (f = msg.getTimestamplte()) && proto.messages.OptionalUInt64.toObject(includeInstance, f),
fromme: (f = msg.getFromme()) && proto.messages.OptionalBool.toObject(includeInstance, f)
fromme: (f = msg.getFromme()) && proto.messages.OptionalBool.toObject(includeInstance, f),
status: (f = msg.getStatus()) && proto.messages.OptionalUInt32.toObject(includeInstance, f)
};
if (includeInstance) {
@@ -14580,6 +14637,11 @@ proto.messages.MessageFilters.deserializeBinaryFromReader = function(msg, reader
reader.readMessage(value,proto.messages.OptionalBool.deserializeBinaryFromReader);
msg.setFromme(value);
break;
case 5:
var value = new proto.messages.OptionalUInt32;
reader.readMessage(value,proto.messages.OptionalUInt32.deserializeBinaryFromReader);
msg.setStatus(value);
break;
default:
reader.skipField();
break;
@@ -14641,6 +14703,14 @@ proto.messages.MessageFilters.serializeBinaryToWriter = function(message, writer
proto.messages.OptionalBool.serializeBinaryToWriter
);
}
f = message.getStatus();
if (f != null) {
writer.writeMessage(
5,
f,
proto.messages.OptionalUInt32.serializeBinaryToWriter
);
}
};
@@ -14792,6 +14862,43 @@ proto.messages.MessageFilters.prototype.hasFromme = function() {
};
/**
* optional OptionalUInt32 status = 5;
* @return {?proto.messages.OptionalUInt32}
*/
proto.messages.MessageFilters.prototype.getStatus = function() {
return /** @type{?proto.messages.OptionalUInt32} */ (
jspb.Message.getWrapperField(this, proto.messages.OptionalUInt32, 5));
};
/**
* @param {?proto.messages.OptionalUInt32|undefined} value
* @return {!proto.messages.MessageFilters} returns this
*/
proto.messages.MessageFilters.prototype.setStatus = function(value) {
return jspb.Message.setWrapperField(this, 5, value);
};
/**
* Clears the message field making it undefined.
* @return {!proto.messages.MessageFilters} returns this
*/
proto.messages.MessageFilters.prototype.clearStatus = function() {
return this.setStatus(undefined);
};
/**
* Returns whether this field is set.
* @return {boolean}
*/
proto.messages.MessageFilters.prototype.hasStatus = function() {
return jspb.Message.getField(this, 5) != null;
};
@@ -1322,6 +1322,8 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
});
}
const status =
filter['filter.ack'] != null ? filter['filter.ack'] + 1 : null;
const request = new messages.GetMessagesRequest({
session: this.session,
filters: new messages.MessageFilters({
@@ -1335,6 +1337,7 @@ export class WhatsappSessionGoWSCore extends WhatsappSession {
messages.OptionalUInt64,
),
fromMe: optional(filter['filter.fromMe'], messages.OptionalBool),
status: optional(status, messages.OptionalUInt32),
}),
pagination: new messages.Pagination({
limit: query.limit,
@@ -35,8 +35,17 @@ export class SqlMessagesMethods {
}
if (filter['filter.fromMe'] != null) {
// filter by data json inside
const sql = this.repository.filterJson('data', 'key.fromMe');
query = query.whereRaw(sql, [filter['filter.fromMe'] ? 'true' : 'false']);
const [sql, value] = this.repository.filterJson(
'data',
'key.fromMe',
filter['filter.fromMe'],
);
query = query.whereRaw(sql, [value]);
}
if (filter['filter.ack'] != null) {
const status = filter['filter.ack'] + 1;
const [sql, value] = this.repository.filterJson('data', 'status', status);
query = query.whereRaw(sql, [value]);
}
query = this.repository.pagination(query, pagination);
return this.repository.all(query);
@@ -199,6 +199,9 @@ export class WebjsClientCore extends Client {
) {
return false;
}
if (filter['filter.ack'] != null && m.ack !== filter['filter.ack']) {
return false;
}
return true;
};
+1 -1
View File
@@ -1,4 +1,4 @@
export interface IJsonQuery {
filter(field: string, key: string): string;
filter(field: string, key: string, value: any): [string, string];
sortBy(field: string, sortBy: string, direction: string): string;
}
+2 -2
View File
@@ -187,8 +187,8 @@ export class SqlKVRepository<Entity> {
/**
* JSON helpers
*/
public filterJson(field: string, key: string): string {
return this.jsonQuery.filter(field, key);
public filterJson(field: string, key: string, value: any): [string, string] {
return this.jsonQuery.filter(field, key, value);
}
protected stringify(data: any): string {
+2 -2
View File
@@ -1,9 +1,9 @@
import { IJsonQuery } from '@waha/core/storage/sql/IJsonQuery';
export class Sqlite3JsonQuery implements IJsonQuery {
filter(field: string, key: string): string {
filter(field: string, key: string, value: any): [string, string] {
const jsonPath = `$.${key}`;
return `${field}->'${jsonPath}' = ?`;
return [`${field}->'${jsonPath}' = ?`, `${value}`];
}
sortBy(field: string, sortBy: string, direction: string): string {
+26
View File
@@ -1,5 +1,7 @@
import { BadRequestException } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger';
import { BooleanString } from '@waha/nestjs/validation/BooleanString';
import { WAMessageAck, WAMessageAckName } from '@waha/structures/enums.dto';
import {
LimitOffsetParams,
PaginationParams,
@@ -39,6 +41,30 @@ export class GetChatMessagesFilter {
@IsBoolean()
@IsOptional()
'filter.fromMe'?: boolean;
@ApiProperty({
required: false,
description: 'Filter messages by acknowledgment status',
enum: WAMessageAckName,
})
@IsEnum(WAMessageAckName)
@IsOptional()
'filter.ack'?: WAMessageAck;
}
export function transformAck(
filter: GetChatMessagesFilter,
): GetChatMessagesFilter {
if (!filter) return filter;
if (!filter['filter.ack']) return filter;
const ackName = filter['filter.ack'];
// @ts-ignore
const ack: WAMessageAck = WAMessageAck[ackName];
if (ack == null) {
throw new BadRequestException(`Invalid ack: '${ackName}'`);
}
filter['filter.ack'] = ack;
return filter;
}
export class ChatPictureQuery {
+9
View File
@@ -68,4 +68,13 @@ export enum WAMessageAck {
PLAYED = 4,
}
export enum WAMessageAckName {
ERROR = 'ERROR',
PENDING = 'PENDING',
SERVER = 'SERVER',
DEVICE = 'DEVICE',
READ = 'READ',
PLAYED = 'PLAYED',
}
export const ACK_UNKNOWN = 'UNKNOWN';