tychat-contracts 1.0.104 → 1.0.106
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/dist/conversations/conversation-contact-filters-query.validator.d.ts +14 -0
- package/dist/conversations/conversation-contact-filters-query.validator.d.ts.map +1 -0
- package/dist/conversations/conversation-contact-filters-query.validator.js +142 -0
- package/dist/conversations/index.d.ts +1 -0
- package/dist/conversations/index.d.ts.map +1 -1
- package/dist/conversations/index.js +1 -0
- package/dist/conversations/list-conversation-contacts-query.dto.d.ts.map +1 -1
- package/dist/conversations/list-conversation-contacts-query.dto.js +6 -11
- package/dist/utils/parse-filters-from-query.util.d.ts.map +1 -1
- package/dist/utils/parse-filters-from-query.util.js +5 -0
- package/package.json +1 -1
- package/src/conversations/conversation-contact-filters-query.validator.ts +166 -0
- package/src/conversations/index.ts +1 -0
- package/src/conversations/list-conversation-contacts-query.dto.ts +7 -21
- package/src/utils/parse-filters-from-query.util.ts +5 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ValidationArguments, ValidatorConstraintInterface } from 'class-validator';
|
|
2
|
+
/**
|
|
3
|
+
* Aceita na query (e no payload Kafka já desserializado):
|
|
4
|
+
* - array de strings: cada string é JSON de um objeto `{ key, op, value }`
|
|
5
|
+
* - array de objetos (ex.: query parser / cliente legado)
|
|
6
|
+
* - string única: JSON array ou JSON objeto único
|
|
7
|
+
*
|
|
8
|
+
* Substitui `filters` no objeto pai por `ConversationContactListFilterDto[]` validado.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ConversationContactFiltersQueryConstraint implements ValidatorConstraintInterface {
|
|
11
|
+
validate(value: unknown, args: ValidationArguments): boolean;
|
|
12
|
+
defaultMessage(args: ValidationArguments): string;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=conversation-contact-filters-query.validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-contact-filters-query.validator.d.ts","sourceRoot":"","sources":["../../src/conversations/conversation-contact-filters-query.validator.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,mBAAmB,EAGnB,4BAA4B,EAC7B,MAAM,iBAAiB,CAAC;AAoBzB;;;;;;;GAOG;AACH,qBACa,yCACX,YAAW,4BAA4B;IAEvC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO;IAwH5D,cAAc,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM;CAMlD"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ConversationContactFiltersQueryConstraint = void 0;
|
|
10
|
+
const class_transformer_1 = require("class-transformer");
|
|
11
|
+
const class_validator_1 = require("class-validator");
|
|
12
|
+
const list_conversation_contacts_filters_dto_1 = require("./list-conversation-contacts-filters.dto");
|
|
13
|
+
/** Evita colocar chave extra no DTO (whitelist / forbidNonWhitelisted no pai). */
|
|
14
|
+
const conversationContactFiltersQueryError = new WeakMap();
|
|
15
|
+
function flattenErrors(errors, prefix = '') {
|
|
16
|
+
const out = [];
|
|
17
|
+
for (const e of errors) {
|
|
18
|
+
const path = prefix ? `${prefix}.${e.property}` : e.property;
|
|
19
|
+
if (e.constraints) {
|
|
20
|
+
out.push(...Object.values(e.constraints).map((m) => `${path}: ${m}`));
|
|
21
|
+
}
|
|
22
|
+
if (e.children?.length) {
|
|
23
|
+
out.push(...flattenErrors(e.children, path));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Aceita na query (e no payload Kafka já desserializado):
|
|
30
|
+
* - array de strings: cada string é JSON de um objeto `{ key, op, value }`
|
|
31
|
+
* - array de objetos (ex.: query parser / cliente legado)
|
|
32
|
+
* - string única: JSON array ou JSON objeto único
|
|
33
|
+
*
|
|
34
|
+
* Substitui `filters` no objeto pai por `ConversationContactListFilterDto[]` validado.
|
|
35
|
+
*/
|
|
36
|
+
let ConversationContactFiltersQueryConstraint = class ConversationContactFiltersQueryConstraint {
|
|
37
|
+
validate(value, args) {
|
|
38
|
+
const parent = args.object;
|
|
39
|
+
conversationContactFiltersQueryError.delete(parent);
|
|
40
|
+
if (value === undefined || value === null) {
|
|
41
|
+
parent.filters = undefined;
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
let rawItems;
|
|
45
|
+
if (typeof value === 'string') {
|
|
46
|
+
const t = value.trim();
|
|
47
|
+
if (t === '') {
|
|
48
|
+
parent.filters = undefined;
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(t);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
conversationContactFiltersQueryError.set(parent, 'filters: string não é JSON válido');
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(parsed)) {
|
|
60
|
+
rawItems = parsed;
|
|
61
|
+
}
|
|
62
|
+
else if (parsed !== null &&
|
|
63
|
+
typeof parsed === 'object' &&
|
|
64
|
+
!Array.isArray(parsed)) {
|
|
65
|
+
rawItems = [parsed];
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
conversationContactFiltersQueryError.set(parent, 'filters: JSON deve ser array ou objeto');
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (Array.isArray(value)) {
|
|
73
|
+
rawItems = value;
|
|
74
|
+
}
|
|
75
|
+
else if (value !== null &&
|
|
76
|
+
typeof value === 'object' &&
|
|
77
|
+
!Array.isArray(value)) {
|
|
78
|
+
rawItems = [value];
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
conversationContactFiltersQueryError.set(parent, 'filters deve ser array de strings JSON, array de objetos, ou string JSON');
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
const out = [];
|
|
85
|
+
for (let i = 0; i < rawItems.length; i++) {
|
|
86
|
+
const el = rawItems[i];
|
|
87
|
+
let plain;
|
|
88
|
+
if (typeof el === 'string') {
|
|
89
|
+
const s = el.trim();
|
|
90
|
+
if (s === '') {
|
|
91
|
+
conversationContactFiltersQueryError.set(parent, `filters[${i}] não pode ser string vazia`);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
plain = JSON.parse(s);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
conversationContactFiltersQueryError.set(parent, `filters[${i}]: JSON inválido`);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (el !== null && typeof el === 'object' && !Array.isArray(el)) {
|
|
103
|
+
plain = el;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
conversationContactFiltersQueryError.set(parent, `filters[${i}] deve ser string JSON ou objeto`);
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (plain === null ||
|
|
110
|
+
typeof plain !== 'object' ||
|
|
111
|
+
Array.isArray(plain)) {
|
|
112
|
+
conversationContactFiltersQueryError.set(parent, `filters[${i}]: após parse deve ser um objeto (não array)`);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
const dto = (0, class_transformer_1.plainToInstance)(list_conversation_contacts_filters_dto_1.ConversationContactListFilterDto, plain);
|
|
116
|
+
const errors = (0, class_validator_1.validateSync)(dto, {
|
|
117
|
+
whitelist: true,
|
|
118
|
+
forbidNonWhitelisted: true,
|
|
119
|
+
});
|
|
120
|
+
if (errors.length) {
|
|
121
|
+
const msg = flattenErrors(errors)
|
|
122
|
+
.map((line) => `filters[${i}] ${line}`)
|
|
123
|
+
.join('; ');
|
|
124
|
+
conversationContactFiltersQueryError.set(parent, msg);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
out.push(dto);
|
|
128
|
+
}
|
|
129
|
+
parent.filters = out;
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
defaultMessage(args) {
|
|
133
|
+
const parent = args.object;
|
|
134
|
+
const msg = conversationContactFiltersQueryError.get(parent);
|
|
135
|
+
conversationContactFiltersQueryError.delete(parent);
|
|
136
|
+
return typeof msg === 'string' ? msg : 'filters inválidos';
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
exports.ConversationContactFiltersQueryConstraint = ConversationContactFiltersQueryConstraint;
|
|
140
|
+
exports.ConversationContactFiltersQueryConstraint = ConversationContactFiltersQueryConstraint = __decorate([
|
|
141
|
+
(0, class_validator_1.ValidatorConstraint)({ name: 'conversationContactFiltersQuery', async: false })
|
|
142
|
+
], ConversationContactFiltersQueryConstraint);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './conversation-type.dto';
|
|
2
2
|
export * from './conversation-intention.dto';
|
|
3
3
|
export * from './list-conversation-contacts-filters.dto';
|
|
4
|
+
export * from './conversation-contact-filters-query.validator';
|
|
4
5
|
export * from './list-conversation-contacts-query.dto';
|
|
5
6
|
export * from './create-conversation-session.dto';
|
|
6
7
|
export * from './conversation-session-response.dto';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conversations/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conversations/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0CAA0C,CAAC;AACzD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,wCAAwC,CAAC;AACvD,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC"}
|
|
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
__exportStar(require("./conversation-type.dto"), exports);
|
|
18
18
|
__exportStar(require("./conversation-intention.dto"), exports);
|
|
19
19
|
__exportStar(require("./list-conversation-contacts-filters.dto"), exports);
|
|
20
|
+
__exportStar(require("./conversation-contact-filters-query.validator"), exports);
|
|
20
21
|
__exportStar(require("./list-conversation-contacts-query.dto"), exports);
|
|
21
22
|
__exportStar(require("./create-conversation-session.dto"), exports);
|
|
22
23
|
__exportStar(require("./conversation-session-response.dto"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-conversation-contacts-query.dto.d.ts","sourceRoot":"","sources":["../../src/conversations/list-conversation-contacts-query.dto.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"list-conversation-contacts-query.dto.d.ts","sourceRoot":"","sources":["../../src/conversations/list-conversation-contacts-query.dto.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gCAAgC,EAAE,MAAM,0CAA0C,CAAC;AAE5F,qBAAa,gCAAgC;IAU3C,IAAI,CAAC,EAAE,MAAM,CAAC;IAad,KAAK,CAAC,EAAE,MAAM,CAAC;IAWf,OAAO,CAAC,EAAE,gCAAgC,EAAE,CAAC;CAC9C"}
|
|
@@ -11,10 +11,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.ListConversationContactsQueryDto = void 0;
|
|
13
13
|
const swagger_1 = require("@nestjs/swagger");
|
|
14
|
-
const class_transformer_1 = require("class-transformer");
|
|
15
14
|
const class_validator_1 = require("class-validator");
|
|
16
|
-
const
|
|
17
|
-
const list_conversation_contacts_filters_dto_1 = require("./list-conversation-contacts-filters.dto");
|
|
15
|
+
const conversation_contact_filters_query_validator_1 = require("./conversation-contact-filters-query.validator");
|
|
18
16
|
class ListConversationContactsQueryDto {
|
|
19
17
|
page;
|
|
20
18
|
limit;
|
|
@@ -49,15 +47,12 @@ __decorate([
|
|
|
49
47
|
], ListConversationContactsQueryDto.prototype, "limit", void 0);
|
|
50
48
|
__decorate([
|
|
51
49
|
(0, swagger_1.ApiPropertyOptional)({
|
|
52
|
-
description: '
|
|
53
|
-
type:
|
|
54
|
-
|
|
50
|
+
description: 'Filtros da sessão mais recente por paciente. Cada item é uma **string** com JSON de um objeto `{ "key", "op", "value" }` (recomendado), ou o servidor aceita objeto já parseado (query/Swagger). Ops: ==, !=, >, <, >=, <=, in. Ex.: `["{\\"key\\":\\"intention\\",\\"op\\":\\"==\\",\\"value\\":\\"clinic_info\\"}"]`',
|
|
51
|
+
type: 'array',
|
|
52
|
+
items: { type: 'string' },
|
|
53
|
+
example: ['{"key":"intention","op":"==","value":"clinic_info"}'],
|
|
55
54
|
}),
|
|
56
55
|
(0, class_validator_1.IsOptional)(),
|
|
57
|
-
(0,
|
|
58
|
-
(0, class_validator_1.IsArray)(),
|
|
59
|
-
(0, class_validator_1.ArrayMinSize)(0),
|
|
60
|
-
(0, class_validator_1.ValidateNested)({ each: true }),
|
|
61
|
-
(0, class_transformer_1.Type)(() => list_conversation_contacts_filters_dto_1.ConversationContactListFilterDto),
|
|
56
|
+
(0, class_validator_1.Validate)(conversation_contact_filters_query_validator_1.ConversationContactFiltersQueryConstraint),
|
|
62
57
|
__metadata("design:type", Array)
|
|
63
58
|
], ListConversationContactsQueryDto.prototype, "filters", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-filters-from-query.util.d.ts","sourceRoot":"","sources":["../../src/utils/parse-filters-from-query.util.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"parse-filters-from-query.util.d.ts","sourceRoot":"","sources":["../../src/utils/parse-filters-from-query.util.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,SAAS,CAyE9E"}
|
|
@@ -37,6 +37,11 @@ function parseFilterObjectsFromQuery(value) {
|
|
|
37
37
|
!Array.isArray(parsed)) {
|
|
38
38
|
return [parsed];
|
|
39
39
|
}
|
|
40
|
+
// Query HTTP: `filters` vem como string; JSON pode ser `["{\"key\":...}"]`
|
|
41
|
+
// (array de strings), não só `[{...}]`. Reutiliza o ramo de array.
|
|
42
|
+
if (Array.isArray(parsed)) {
|
|
43
|
+
return parseFilterObjectsFromQuery(parsed);
|
|
44
|
+
}
|
|
40
45
|
return undefined;
|
|
41
46
|
}
|
|
42
47
|
catch {
|
package/package.json
CHANGED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { plainToInstance } from 'class-transformer';
|
|
2
|
+
import {
|
|
3
|
+
validateSync,
|
|
4
|
+
ValidationArguments,
|
|
5
|
+
ValidationError,
|
|
6
|
+
ValidatorConstraint,
|
|
7
|
+
ValidatorConstraintInterface,
|
|
8
|
+
} from 'class-validator';
|
|
9
|
+
import { ConversationContactListFilterDto } from './list-conversation-contacts-filters.dto';
|
|
10
|
+
|
|
11
|
+
/** Evita colocar chave extra no DTO (whitelist / forbidNonWhitelisted no pai). */
|
|
12
|
+
const conversationContactFiltersQueryError = new WeakMap<object, string>();
|
|
13
|
+
|
|
14
|
+
function flattenErrors(errors: ValidationError[], prefix = ''): string[] {
|
|
15
|
+
const out: string[] = [];
|
|
16
|
+
for (const e of errors) {
|
|
17
|
+
const path = prefix ? `${prefix}.${e.property}` : e.property;
|
|
18
|
+
if (e.constraints) {
|
|
19
|
+
out.push(...Object.values(e.constraints).map((m) => `${path}: ${m}`));
|
|
20
|
+
}
|
|
21
|
+
if (e.children?.length) {
|
|
22
|
+
out.push(...flattenErrors(e.children, path));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Aceita na query (e no payload Kafka já desserializado):
|
|
30
|
+
* - array de strings: cada string é JSON de um objeto `{ key, op, value }`
|
|
31
|
+
* - array de objetos (ex.: query parser / cliente legado)
|
|
32
|
+
* - string única: JSON array ou JSON objeto único
|
|
33
|
+
*
|
|
34
|
+
* Substitui `filters` no objeto pai por `ConversationContactListFilterDto[]` validado.
|
|
35
|
+
*/
|
|
36
|
+
@ValidatorConstraint({ name: 'conversationContactFiltersQuery', async: false })
|
|
37
|
+
export class ConversationContactFiltersQueryConstraint
|
|
38
|
+
implements ValidatorConstraintInterface
|
|
39
|
+
{
|
|
40
|
+
validate(value: unknown, args: ValidationArguments): boolean {
|
|
41
|
+
const parent = args.object as Record<string, unknown>;
|
|
42
|
+
conversationContactFiltersQueryError.delete(parent);
|
|
43
|
+
|
|
44
|
+
if (value === undefined || value === null) {
|
|
45
|
+
parent.filters = undefined;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let rawItems: unknown[];
|
|
50
|
+
if (typeof value === 'string') {
|
|
51
|
+
const t = value.trim();
|
|
52
|
+
if (t === '') {
|
|
53
|
+
parent.filters = undefined;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
let parsed: unknown;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(t);
|
|
59
|
+
} catch {
|
|
60
|
+
conversationContactFiltersQueryError.set(
|
|
61
|
+
parent,
|
|
62
|
+
'filters: string não é JSON válido',
|
|
63
|
+
);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(parsed)) {
|
|
67
|
+
rawItems = parsed;
|
|
68
|
+
} else if (
|
|
69
|
+
parsed !== null &&
|
|
70
|
+
typeof parsed === 'object' &&
|
|
71
|
+
!Array.isArray(parsed)
|
|
72
|
+
) {
|
|
73
|
+
rawItems = [parsed];
|
|
74
|
+
} else {
|
|
75
|
+
conversationContactFiltersQueryError.set(
|
|
76
|
+
parent,
|
|
77
|
+
'filters: JSON deve ser array ou objeto',
|
|
78
|
+
);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
} else if (Array.isArray(value)) {
|
|
82
|
+
rawItems = value;
|
|
83
|
+
} else if (
|
|
84
|
+
value !== null &&
|
|
85
|
+
typeof value === 'object' &&
|
|
86
|
+
!Array.isArray(value)
|
|
87
|
+
) {
|
|
88
|
+
rawItems = [value];
|
|
89
|
+
} else {
|
|
90
|
+
conversationContactFiltersQueryError.set(
|
|
91
|
+
parent,
|
|
92
|
+
'filters deve ser array de strings JSON, array de objetos, ou string JSON',
|
|
93
|
+
);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const out: ConversationContactListFilterDto[] = [];
|
|
98
|
+
for (let i = 0; i < rawItems.length; i++) {
|
|
99
|
+
const el = rawItems[i];
|
|
100
|
+
let plain: unknown;
|
|
101
|
+
if (typeof el === 'string') {
|
|
102
|
+
const s = el.trim();
|
|
103
|
+
if (s === '') {
|
|
104
|
+
conversationContactFiltersQueryError.set(
|
|
105
|
+
parent,
|
|
106
|
+
`filters[${i}] não pode ser string vazia`,
|
|
107
|
+
);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
plain = JSON.parse(s);
|
|
112
|
+
} catch {
|
|
113
|
+
conversationContactFiltersQueryError.set(
|
|
114
|
+
parent,
|
|
115
|
+
`filters[${i}]: JSON inválido`,
|
|
116
|
+
);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
} else if (el !== null && typeof el === 'object' && !Array.isArray(el)) {
|
|
120
|
+
plain = el;
|
|
121
|
+
} else {
|
|
122
|
+
conversationContactFiltersQueryError.set(
|
|
123
|
+
parent,
|
|
124
|
+
`filters[${i}] deve ser string JSON ou objeto`,
|
|
125
|
+
);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (
|
|
130
|
+
plain === null ||
|
|
131
|
+
typeof plain !== 'object' ||
|
|
132
|
+
Array.isArray(plain)
|
|
133
|
+
) {
|
|
134
|
+
conversationContactFiltersQueryError.set(
|
|
135
|
+
parent,
|
|
136
|
+
`filters[${i}]: após parse deve ser um objeto (não array)`,
|
|
137
|
+
);
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const dto = plainToInstance(ConversationContactListFilterDto, plain);
|
|
142
|
+
const errors = validateSync(dto, {
|
|
143
|
+
whitelist: true,
|
|
144
|
+
forbidNonWhitelisted: true,
|
|
145
|
+
});
|
|
146
|
+
if (errors.length) {
|
|
147
|
+
const msg = flattenErrors(errors)
|
|
148
|
+
.map((line) => `filters[${i}] ${line}`)
|
|
149
|
+
.join('; ');
|
|
150
|
+
conversationContactFiltersQueryError.set(parent, msg);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
out.push(dto);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
parent.filters = out;
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
defaultMessage(args: ValidationArguments): string {
|
|
161
|
+
const parent = args.object as object;
|
|
162
|
+
const msg = conversationContactFiltersQueryError.get(parent);
|
|
163
|
+
conversationContactFiltersQueryError.delete(parent);
|
|
164
|
+
return typeof msg === 'string' ? msg : 'filters inválidos';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './conversation-type.dto';
|
|
2
2
|
export * from './conversation-intention.dto';
|
|
3
3
|
export * from './list-conversation-contacts-filters.dto';
|
|
4
|
+
export * from './conversation-contact-filters-query.validator';
|
|
4
5
|
export * from './list-conversation-contacts-query.dto';
|
|
5
6
|
export * from './create-conversation-session.dto';
|
|
6
7
|
export * from './conversation-session-response.dto';
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
ArrayMinSize,
|
|
5
|
-
IsArray,
|
|
6
|
-
IsInt,
|
|
7
|
-
IsOptional,
|
|
8
|
-
Max,
|
|
9
|
-
Min,
|
|
10
|
-
ValidateNested,
|
|
11
|
-
} from 'class-validator';
|
|
12
|
-
import { parseFilterObjectsFromQuery } from '../utils/parse-filters-from-query.util';
|
|
2
|
+
import { IsInt, IsOptional, Max, Min, Validate } from 'class-validator';
|
|
3
|
+
import { ConversationContactFiltersQueryConstraint } from './conversation-contact-filters-query.validator';
|
|
13
4
|
import { ConversationContactListFilterDto } from './list-conversation-contacts-filters.dto';
|
|
14
5
|
|
|
15
6
|
export class ListConversationContactsQueryDto {
|
|
@@ -39,17 +30,12 @@ export class ListConversationContactsQueryDto {
|
|
|
39
30
|
|
|
40
31
|
@ApiPropertyOptional({
|
|
41
32
|
description:
|
|
42
|
-
'
|
|
43
|
-
type:
|
|
44
|
-
|
|
33
|
+
'Filtros da sessão mais recente por paciente. Cada item é uma **string** com JSON de um objeto `{ "key", "op", "value" }` (recomendado), ou o servidor aceita objeto já parseado (query/Swagger). Ops: ==, !=, >, <, >=, <=, in. Ex.: `["{\\"key\\":\\"intention\\",\\"op\\":\\"==\\",\\"value\\":\\"clinic_info\\"}"]`',
|
|
34
|
+
type: 'array',
|
|
35
|
+
items: { type: 'string' },
|
|
36
|
+
example: ['{"key":"intention","op":"==","value":"clinic_info"}'],
|
|
45
37
|
})
|
|
46
38
|
@IsOptional()
|
|
47
|
-
@
|
|
48
|
-
parseFilterObjectsFromQuery<ConversationContactListFilterDto>(value),
|
|
49
|
-
)
|
|
50
|
-
@IsArray()
|
|
51
|
-
@ArrayMinSize(0)
|
|
52
|
-
@ValidateNested({ each: true })
|
|
53
|
-
@Type(() => ConversationContactListFilterDto)
|
|
39
|
+
@Validate(ConversationContactFiltersQueryConstraint)
|
|
54
40
|
filters?: ConversationContactListFilterDto[];
|
|
55
41
|
}
|
|
@@ -40,6 +40,11 @@ export function parseFilterObjectsFromQuery<T>(value: unknown): T[] | undefined
|
|
|
40
40
|
) {
|
|
41
41
|
return [parsed as T];
|
|
42
42
|
}
|
|
43
|
+
// Query HTTP: `filters` vem como string; JSON pode ser `["{\"key\":...}"]`
|
|
44
|
+
// (array de strings), não só `[{...}]`. Reutiliza o ramo de array.
|
|
45
|
+
if (Array.isArray(parsed)) {
|
|
46
|
+
return parseFilterObjectsFromQuery<T>(parsed);
|
|
47
|
+
}
|
|
43
48
|
return undefined;
|
|
44
49
|
} catch {
|
|
45
50
|
return undefined;
|