@talkpilot/core-db 1.0.14 → 1.0.16
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/municipal/departmentsSubjects/departmentsSubjects.getters.d.ts +2 -2
- package/dist/municipal/departmentsSubjects/departmentsSubjects.getters.d.ts.map +1 -1
- package/dist/municipal/departmentsSubjects/departmentsSubjects.getters.js.map +1 -1
- package/dist/municipal/departmentsSubjects/departmentsSubjects.types.d.ts +1 -4
- package/dist/municipal/departmentsSubjects/departmentsSubjects.types.d.ts.map +1 -1
- package/dist/municipal/departmentsSubjects/index.d.ts +1 -1
- package/dist/municipal/departmentsSubjects/index.d.ts.map +1 -1
- package/dist/municipal/index.d.ts +2 -0
- package/dist/municipal/index.d.ts.map +1 -1
- package/dist/municipal/index.js +1 -0
- package/dist/municipal/index.js.map +1 -1
- package/dist/municipal/streets/streets.getters.d.ts.map +1 -1
- package/dist/municipal/streets/streets.getters.js.map +1 -1
- package/dist/municipal/systemInstructions/index.d.ts +4 -0
- package/dist/municipal/systemInstructions/index.d.ts.map +1 -0
- package/dist/municipal/systemInstructions/index.js +19 -0
- package/dist/municipal/systemInstructions/index.js.map +1 -0
- package/dist/municipal/systemInstructions/instructions.getters.d.ts +30 -0
- package/dist/municipal/systemInstructions/instructions.getters.d.ts.map +1 -0
- package/dist/municipal/systemInstructions/instructions.getters.js +46 -0
- package/dist/municipal/systemInstructions/instructions.getters.js.map +1 -0
- package/dist/municipal/systemInstructions/instructions.setters.d.ts +36 -0
- package/dist/municipal/systemInstructions/instructions.setters.d.ts.map +1 -0
- package/dist/municipal/systemInstructions/instructions.setters.js +64 -0
- package/dist/municipal/systemInstructions/instructions.setters.js.map +1 -0
- package/dist/municipal/systemInstructions/instructions.types.d.ts +14 -0
- package/dist/municipal/systemInstructions/instructions.types.d.ts.map +1 -0
- package/dist/municipal/systemInstructions/instructions.types.js +3 -0
- package/dist/municipal/systemInstructions/instructions.types.js.map +1 -0
- package/dist/municipal/tickets/tickets.getters.d.ts.map +1 -1
- package/dist/municipal/tickets/tickets.getters.js.map +1 -1
- package/dist/municipal/tickets/tickets.types.d.ts +1 -1
- package/dist/municipal/tickets/tickets.types.d.ts.map +1 -1
- package/dist/municipal/utils/types.d.ts +5 -0
- package/dist/municipal/utils/types.d.ts.map +1 -0
- package/dist/municipal/utils/types.js +3 -0
- package/dist/municipal/utils/types.js.map +1 -0
- package/dist/talkpilot/clients/clients.types.d.ts +1 -0
- package/dist/talkpilot/clients/clients.types.d.ts.map +1 -1
- package/dist/talkpilot/flows/flows.schema.d.ts +3 -0
- package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -1
- package/dist/talkpilot/flows/flows.schema.js +1 -0
- package/dist/talkpilot/flows/flows.schema.js.map +1 -1
- package/dist/talkpilot/flows/flows.types.d.ts +1 -0
- package/dist/talkpilot/flows/flows.types.d.ts.map +1 -1
- package/dist/test-utils/factories/municipal/departmentsSubjects.d.ts.map +1 -1
- package/dist/test-utils/factories/municipal/departmentsSubjects.js.map +1 -1
- package/package.json +1 -1
- package/src/municipal/departmentsSubjects/departmentsSubjects.getters.ts +2 -2
- package/src/municipal/departmentsSubjects/departmentsSubjects.types.ts +4 -8
- package/src/municipal/departmentsSubjects/index.ts +0 -1
- package/src/municipal/index.ts +3 -1
- package/src/municipal/streets/streets.getters.ts +1 -1
- package/src/municipal/systemInstructions/__tests__/getters.spec.ts +106 -0
- package/src/municipal/systemInstructions/__tests__/setters.spec.ts +201 -0
- package/src/municipal/systemInstructions/index.ts +3 -0
- package/src/municipal/systemInstructions/instructions.getters.ts +45 -0
- package/src/municipal/systemInstructions/instructions.setters.ts +79 -0
- package/src/municipal/systemInstructions/instructions.types.ts +15 -0
- package/src/municipal/tickets/tickets.getters.ts +1 -1
- package/src/municipal/tickets/tickets.types.ts +2 -1
- package/src/municipal/utils/types.ts +6 -0
- package/src/talkpilot/clients/clients.types.ts +1 -0
- package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +13 -0
- package/src/talkpilot/flows/flows.schema.ts +1 -0
- package/src/talkpilot/flows/flows.types.ts +1 -0
- package/src/talkpilot/phone_numbers/__tests__/phone_numbers.spec.ts +2 -1
- package/src/talkpilot/sessions/__tests__/sessions.spec.ts +1 -1
- package/src/test-utils/factories/municipal/departmentsSubjects.ts +2 -1
- package/src/test-utils/factories/municipal/tickets.ts +1 -1
- package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts +0 -4
- package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts.map +0 -1
- package/dist/talkpilot/subscriptions/subscriptions.utils.js +0 -20
- package/dist/talkpilot/subscriptions/subscriptions.utils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"departmentsSubjects.d.ts","sourceRoot":"","sources":["../../../../src/test-utils/factories/municipal/departmentsSubjects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,kEAAkE,CAAC;
|
|
1
|
+
{"version":3,"file":"departmentsSubjects.d.ts","sourceRoot":"","sources":["../../../../src/test-utils/factories/municipal/departmentsSubjects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,kEAAkE,CAAC;AAK1E,eAAO,MAAM,wBAAwB,4GAclC,CAAC;AAEJ,wBAAgB,uBAAuB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAEjG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"departmentsSubjects.js","sourceRoot":"","sources":["../../../../src/test-utils/factories/municipal/departmentsSubjects.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"departmentsSubjects.js","sourceRoot":"","sources":["../../../../src/test-utils/factories/municipal/departmentsSubjects.ts"],"names":[],"mappings":";;;AA2BA,0DAEC;AA7BD,qCAAkC;AAClC,qCAAmC;AACnC,2CAAwC;AAOxC,MAAM,YAAY,GAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AAEzE,QAAA,wBAAwB,GAAG,iBAAO,CAAC,MAAM,CAAoB,GAAG,EAAE,CAAC,CAAC;IAC/E,GAAG,EAAE,IAAI,kBAAQ,EAAE;IACnB,SAAS,EAAE,IAAI,IAAI,EAAE;IACrB,SAAS,EAAE,IAAI,IAAI,EAAE;IACrB,WAAW,EAAE,aAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACjC,UAAU,EAAE,aAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,gBAAgB,EAAE,aAAK,CAAC,KAAK,CAAC,IAAI,EAAE;IACpC,cAAc,EAAE,aAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,YAAY,EAAE,CAAC,aAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACtC,QAAQ,EAAE,aAAK,CAAC,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC;IAClD,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,EAAE;IAChB,cAAc,EAAE,EAAE;IAClB,GAAG,EAAE,aAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;CAC7C,CAAC,CAAC,CAAC;AAEJ,SAAgB,uBAAuB,CAAC,SAAsC;IAC5E,OAAO,gCAAwB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACnD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { getDb, DepartmentSubject } from '../index';
|
|
1
|
+
import { getDb, DepartmentSubject, CityName } from '../index';
|
|
2
2
|
import { Collection, Filter } from 'mongodb';
|
|
3
|
-
import {
|
|
3
|
+
import { VectorSearchResult } from './departmentsSubjects.types';
|
|
4
4
|
|
|
5
5
|
export const getDepartmentsSubjectsCollection = (): Collection<DepartmentSubject> => {
|
|
6
6
|
return getDb().collection<DepartmentSubject>('departmentsSubjects');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {ObjectId, WithId} from 'mongodb';
|
|
2
|
+
import {Request} from 'express';
|
|
3
|
+
import {ClientConfigDoc, Products} from '../../talkpilot/clientsConfig/clientsConfig.types';
|
|
4
|
+
import {CityName} from "../utils/types";
|
|
4
5
|
|
|
5
6
|
export type DepartmentSubject = {
|
|
6
7
|
_id: ObjectId;
|
|
@@ -56,11 +57,6 @@ export type VectorSearchResult = {
|
|
|
56
57
|
score?: number;
|
|
57
58
|
};
|
|
58
59
|
|
|
59
|
-
/**
|
|
60
|
-
* City name type for municipal data
|
|
61
|
-
*/
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
63
|
-
export type CityName = 'ashdod' | 'maltar' | 'billit' | 'hashkelon' | 'eilat' | 'tests' | string;
|
|
64
60
|
export type CommunicationType = 'free_text_sms' | 'upload_url_sms';
|
|
65
61
|
|
|
66
62
|
/**
|
package/src/municipal/index.ts
CHANGED
|
@@ -4,15 +4,17 @@ export * from './cities';
|
|
|
4
4
|
export * from './streets';
|
|
5
5
|
export * from './departmentsSubjects';
|
|
6
6
|
export * from './tickets';
|
|
7
|
+
export * from './systemInstructions';
|
|
8
|
+
export {CityName} from "./utils/types";
|
|
7
9
|
export { municipalDataMongodbClient } from './mongodb-client';
|
|
8
10
|
|
|
9
11
|
let db: Db;
|
|
10
12
|
export const setDb = (d: Db) => {
|
|
11
13
|
db = d;
|
|
12
14
|
};
|
|
15
|
+
|
|
13
16
|
export const getDb = (): Db => {
|
|
14
17
|
if (!db) throw new Error('Municipal Data DB not initialised');
|
|
15
18
|
return db;
|
|
16
19
|
};
|
|
17
|
-
|
|
18
20
|
export const ObjectId = MongoObjectId;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { createSystemInstruction } from '../instructions.setters';
|
|
2
|
+
import {
|
|
3
|
+
getSystemInstructionById,
|
|
4
|
+
getActiveSystemInstructionsByCity,
|
|
5
|
+
getAllActiveSystemInstructions,
|
|
6
|
+
getSystemInstructionsByToolAndCity,
|
|
7
|
+
findSystemInstructions
|
|
8
|
+
} from '../instructions.getters';
|
|
9
|
+
import { ObjectId } from 'mongodb';
|
|
10
|
+
|
|
11
|
+
describe('System Instructions Getter Tests', () => {
|
|
12
|
+
const testCity = 'Ashdod';
|
|
13
|
+
const otherCity = 'Tel Aviv';
|
|
14
|
+
|
|
15
|
+
describe('getters', () => {
|
|
16
|
+
let instructionId: string;
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
const id = await createSystemInstruction({
|
|
20
|
+
cityName: testCity,
|
|
21
|
+
instruction: 'Find Me',
|
|
22
|
+
isActive: true,
|
|
23
|
+
tool: "search tool",
|
|
24
|
+
queryType: "search tool",
|
|
25
|
+
tags: ['important', 'urgent']
|
|
26
|
+
});
|
|
27
|
+
instructionId = id.toString();
|
|
28
|
+
|
|
29
|
+
// for filtering tests
|
|
30
|
+
await createSystemInstruction({
|
|
31
|
+
cityName: testCity,
|
|
32
|
+
instruction: 'Inactive One',
|
|
33
|
+
isActive: false,
|
|
34
|
+
tool: "search tool",
|
|
35
|
+
queryType: "search tool",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await createSystemInstruction({
|
|
39
|
+
cityName: otherCity,
|
|
40
|
+
instruction: 'Other City Instruction',
|
|
41
|
+
isActive: true,
|
|
42
|
+
tool: "other tool",
|
|
43
|
+
queryType: "other type",
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('getSystemInstructionById', () => {
|
|
48
|
+
it('given existing id when fetched then return the document', async () => {
|
|
49
|
+
const result = await getSystemInstructionById(instructionId);
|
|
50
|
+
expect(result?._id.toString()).toBe(instructionId);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('given non-existent id when fetched then return null', async () => {
|
|
54
|
+
const result = await getSystemInstructionById(new ObjectId().toHexString());
|
|
55
|
+
expect(result).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('getActiveSystemInstructionsByCity', () => {
|
|
60
|
+
it('given city with active instructions when fetched then return only active documents for that city', async () => {
|
|
61
|
+
const result = await getActiveSystemInstructionsByCity(testCity);
|
|
62
|
+
expect(result.length).toBe(1);
|
|
63
|
+
expect(result[0].instruction).toBe('Find Me');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('given city with no instructions when fetched then return empty array', async () => {
|
|
67
|
+
const result = await getActiveSystemInstructionsByCity('NonExistentCity');
|
|
68
|
+
expect(result).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('getSystemInstructionsByToolAndCity', () => {
|
|
73
|
+
it('given valid city and tool when fetched then return matching instructions', async () => {
|
|
74
|
+
const result = await getSystemInstructionsByToolAndCity(testCity, 'search tool');
|
|
75
|
+
expect(result.length).toBe(2); // One active, one inactive
|
|
76
|
+
expect(result.every(r => r.cityName === testCity && r.tool === 'search tool')).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('given valid city but wrong tool when fetched then return empty array', async () => {
|
|
80
|
+
const result = await getSystemInstructionsByToolAndCity(testCity, 'wrong tool');
|
|
81
|
+
expect(result).toEqual([]);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('findSystemInstructions', () => {
|
|
86
|
+
it('given filter by tags when searched then return matching documents', async () => {
|
|
87
|
+
const result = await findSystemInstructions({ tags: { $in: ['important'] } });
|
|
88
|
+
expect(result.length).toBe(1);
|
|
89
|
+
expect(result[0].instruction).toBe('Find Me');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('given empty filter when searched then return all documents', async () => {
|
|
93
|
+
const result = await findSystemInstructions({});
|
|
94
|
+
expect(result.length).toBe(3);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('getAllActiveSystemInstructions', () => {
|
|
99
|
+
it('when fetched then return all active instructions from all cities', async () => {
|
|
100
|
+
const result = await getAllActiveSystemInstructions();
|
|
101
|
+
expect(result.length).toBe(2); // One from Ashdod, one from Tel Aviv
|
|
102
|
+
expect(result.every(r => r.isActive)).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createSystemInstruction,
|
|
3
|
+
updateSystemInstruction,
|
|
4
|
+
deleteSystemInstruction,
|
|
5
|
+
deactivateSystemInstruction,
|
|
6
|
+
activateSystemInstruction
|
|
7
|
+
} from '../instructions.setters';
|
|
8
|
+
import { getSystemInstructionById } from '../instructions.getters';
|
|
9
|
+
import {SystemInstruction} from "../instructions.types";
|
|
10
|
+
import { ObjectId } from 'mongodb';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
describe('System Instructions Setter Tests', () => {
|
|
14
|
+
const testCity = 'Ashdod';
|
|
15
|
+
|
|
16
|
+
describe('createSystemInstruction', () => {
|
|
17
|
+
it('given valid data when created then save document with timestamps', async () => {
|
|
18
|
+
// Given
|
|
19
|
+
const instructionData: Omit<SystemInstruction, '_id' | 'createdAt' | 'updatedAt'> = {
|
|
20
|
+
cityName: testCity,
|
|
21
|
+
instruction: 'Test Instruction',
|
|
22
|
+
isActive: true,
|
|
23
|
+
tool: "search tool",
|
|
24
|
+
queryType: "search tool",
|
|
25
|
+
tags: ['test', 'unit']
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// When
|
|
29
|
+
const id = await createSystemInstruction(instructionData);
|
|
30
|
+
|
|
31
|
+
// Then
|
|
32
|
+
const saved = await getSystemInstructionById(id.toString());
|
|
33
|
+
expect(saved).toBeDefined();
|
|
34
|
+
expect(saved?._id).toBeDefined();
|
|
35
|
+
expect(saved).toMatchObject(instructionData);
|
|
36
|
+
expect(saved?.createdAt).toBeInstanceOf(Date);
|
|
37
|
+
expect(saved?.updatedAt).toBeInstanceOf(Date);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('given data without tags when created then save document with default isActive true and no tags', async () => {
|
|
41
|
+
// Given
|
|
42
|
+
const instructionData: Omit<SystemInstruction, '_id' | 'createdAt' | 'updatedAt'> = {
|
|
43
|
+
cityName: testCity,
|
|
44
|
+
instruction: 'No Tags Instruction',
|
|
45
|
+
isActive: true,
|
|
46
|
+
tool: "minimal tool",
|
|
47
|
+
queryType: "minimal type",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// When
|
|
51
|
+
const id = await createSystemInstruction(instructionData);
|
|
52
|
+
|
|
53
|
+
// Then
|
|
54
|
+
const saved = await getSystemInstructionById(id.toString());
|
|
55
|
+
expect(saved).toBeDefined();
|
|
56
|
+
expect(saved?.tags).toBeUndefined();
|
|
57
|
+
expect(saved?.isActive).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('updateSystemInstruction', () => {
|
|
62
|
+
let instructionId: string;
|
|
63
|
+
//Given before each test
|
|
64
|
+
beforeEach(async () => {
|
|
65
|
+
const id = await createSystemInstruction({
|
|
66
|
+
cityName: testCity,
|
|
67
|
+
instruction: 'Find Me',
|
|
68
|
+
isActive: true,
|
|
69
|
+
tool: "search tool",
|
|
70
|
+
queryType: "search tool",
|
|
71
|
+
});
|
|
72
|
+
instructionId = id.toString();
|
|
73
|
+
|
|
74
|
+
await createSystemInstruction({
|
|
75
|
+
cityName: testCity,
|
|
76
|
+
instruction: 'Inactive One',
|
|
77
|
+
isActive: false,
|
|
78
|
+
tool: "search tool",
|
|
79
|
+
queryType: "search tool",
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it('given existing doc when updated then change values and refresh updatedAt', async () => {
|
|
83
|
+
|
|
84
|
+
const originalDoc = await getSystemInstructionById(instructionId.toString());
|
|
85
|
+
|
|
86
|
+
// Wait a bit to ensure timestamp difference
|
|
87
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
88
|
+
|
|
89
|
+
// When
|
|
90
|
+
await updateSystemInstruction(instructionId.toString(), { instruction: 'New Text' });
|
|
91
|
+
|
|
92
|
+
// Then
|
|
93
|
+
const updatedDoc = await getSystemInstructionById(instructionId.toString());
|
|
94
|
+
expect(updatedDoc?.instruction).toBe('New Text');
|
|
95
|
+
expect(updatedDoc?.updatedAt.getTime()).toBeGreaterThan(originalDoc!.updatedAt.getTime());
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('given multiple fields when updated then change all provided values', async () => {
|
|
99
|
+
// When
|
|
100
|
+
await updateSystemInstruction(instructionId, {
|
|
101
|
+
isActive: false,
|
|
102
|
+
tool: 'updated tool',
|
|
103
|
+
tags: ['new-tag']
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Then
|
|
107
|
+
const updatedDoc = await getSystemInstructionById(instructionId);
|
|
108
|
+
expect(updatedDoc?.isActive).toBe(false);
|
|
109
|
+
expect(updatedDoc?.tool).toBe('updated tool');
|
|
110
|
+
expect(updatedDoc?.tags).toEqual(['new-tag']);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('given system instructions, when deactivating it then its status updated to active', async () => {
|
|
114
|
+
//When
|
|
115
|
+
const success= await deactivateSystemInstruction(instructionId.toString());
|
|
116
|
+
const updatedDoc= await getSystemInstructionById(instructionId.toString());
|
|
117
|
+
//Then
|
|
118
|
+
expect(success).toBe(true);
|
|
119
|
+
expect(updatedDoc?.isActive).toBe(false);
|
|
120
|
+
})
|
|
121
|
+
it('given invalidId when deactivating it then return false', async () => {
|
|
122
|
+
//When
|
|
123
|
+
const success= await deactivateSystemInstruction(new ObjectId().toHexString());
|
|
124
|
+
|
|
125
|
+
//Then
|
|
126
|
+
expect(success).toBe(false);
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('given already inactive instruction when deactivating then still return true and remain inactive', async () => {
|
|
130
|
+
// Given
|
|
131
|
+
await deactivateSystemInstruction(instructionId);
|
|
132
|
+
|
|
133
|
+
// When
|
|
134
|
+
const success = await deactivateSystemInstruction(instructionId);
|
|
135
|
+
|
|
136
|
+
// Then
|
|
137
|
+
expect(success).toBe(true);
|
|
138
|
+
const doc = await getSystemInstructionById(instructionId);
|
|
139
|
+
expect(doc?.isActive).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('activateSystemInstruction', () => {
|
|
145
|
+
let instructionId: string;
|
|
146
|
+
beforeEach(async () => {
|
|
147
|
+
const id = await createSystemInstruction({
|
|
148
|
+
cityName: testCity,
|
|
149
|
+
instruction: 'Inactive Instruction',
|
|
150
|
+
isActive: false,
|
|
151
|
+
tool: "test",
|
|
152
|
+
queryType: "test",
|
|
153
|
+
});
|
|
154
|
+
instructionId = id.toString();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('given inactive doc when activating then set isActive to true', async () => {
|
|
158
|
+
// When
|
|
159
|
+
const success = await activateSystemInstruction(instructionId);
|
|
160
|
+
|
|
161
|
+
// Then
|
|
162
|
+
expect(success).toBe(true);
|
|
163
|
+
const updatedDoc = await getSystemInstructionById(instructionId);
|
|
164
|
+
expect(updatedDoc?.isActive).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('given invalidId when activating then return false', async () => {
|
|
168
|
+
// When
|
|
169
|
+
const success = await activateSystemInstruction(new ObjectId().toHexString());
|
|
170
|
+
|
|
171
|
+
// Then
|
|
172
|
+
expect(success).toBe(false);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('deleteSystemInstruction', () => {
|
|
177
|
+
it('given existing id when deleted then remove document from DB', async () => {
|
|
178
|
+
const id = await createSystemInstruction({
|
|
179
|
+
cityName: testCity,
|
|
180
|
+
instruction: 'To be deleted',
|
|
181
|
+
isActive: true,
|
|
182
|
+
tool: "search tool",
|
|
183
|
+
queryType: "search tool",
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const deleteResult = await deleteSystemInstruction(id.toString());
|
|
187
|
+
expect(deleteResult).toBe(true);
|
|
188
|
+
|
|
189
|
+
const findResult = await getSystemInstructionById(id.toString());
|
|
190
|
+
expect(findResult).toBeNull();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('given non-existent id when deleting then return false', async () => {
|
|
194
|
+
// When
|
|
195
|
+
const result = await deleteSystemInstruction(new ObjectId().toHexString());
|
|
196
|
+
|
|
197
|
+
// Then
|
|
198
|
+
expect(result).toBe(false);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {CityName, getDb, ObjectId} from '../index';
|
|
2
|
+
import { Collection, Filter } from 'mongodb';
|
|
3
|
+
import { SystemInstruction } from './instructions.types';
|
|
4
|
+
|
|
5
|
+
export const getSystemInstructionsCollection = (): Collection<SystemInstruction> => {
|
|
6
|
+
return getDb().collection<SystemInstruction>('system_instructions');
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Find system instructions by filter
|
|
10
|
+
* @param filter filter to apply
|
|
11
|
+
* @returns array of system instructions
|
|
12
|
+
*/
|
|
13
|
+
export const findSystemInstructions = async (
|
|
14
|
+
filter: Filter<SystemInstruction> = {}
|
|
15
|
+
): Promise<SystemInstruction[]> => {
|
|
16
|
+
return await getSystemInstructionsCollection().find(filter).toArray();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get system instruction by id
|
|
21
|
+
* @param id system instruction id
|
|
22
|
+
* @returns system instruction or null if not found
|
|
23
|
+
*/
|
|
24
|
+
export const getSystemInstructionById = async (id: string): Promise<SystemInstruction | null> => {
|
|
25
|
+
return await getSystemInstructionsCollection().findOne({ _id: new ObjectId(id) });
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get all active system instructions for a city
|
|
29
|
+
* @param cityName city name
|
|
30
|
+
* @returns array of active system instructions
|
|
31
|
+
*/
|
|
32
|
+
export const getActiveSystemInstructionsByCity = async (cityName: CityName): Promise<SystemInstruction[]> => {
|
|
33
|
+
return await getSystemInstructionsCollection().find({cityName, isActive: true}).toArray();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get system instructions by tool and city
|
|
37
|
+
* @param cityName city name
|
|
38
|
+
* @param toolName tool name
|
|
39
|
+
* @returns array of system instructions
|
|
40
|
+
*/
|
|
41
|
+
export const getSystemInstructionsByToolAndCity = async (cityName: CityName, toolName: string): Promise<SystemInstruction[]> => {
|
|
42
|
+
return await getSystemInstructionsCollection().find({cityName: cityName, tool: toolName}).toArray();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ObjectId } from '../index';
|
|
2
|
+
import { ObjectId as MongoObjectId } from 'mongodb';
|
|
3
|
+
import { SystemInstruction } from './instructions.types';
|
|
4
|
+
import { getSystemInstructionsCollection } from './instructions.getters';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create a new system instruction
|
|
8
|
+
* @param instructionData system instruction data
|
|
9
|
+
* @returns inserted system instruction id
|
|
10
|
+
*/
|
|
11
|
+
export const createSystemInstruction = async (
|
|
12
|
+
instructionData: Omit<SystemInstruction, '_id' | 'createdAt' | 'updatedAt'>
|
|
13
|
+
): Promise<MongoObjectId> => {
|
|
14
|
+
const instruction: Omit<SystemInstruction, '_id'> = { //append doc metadata to user provided data
|
|
15
|
+
...instructionData,
|
|
16
|
+
createdAt: new Date(),
|
|
17
|
+
updatedAt: new Date(),
|
|
18
|
+
};
|
|
19
|
+
const { insertedId } = await getSystemInstructionsCollection().insertOne(
|
|
20
|
+
instruction as SystemInstruction
|
|
21
|
+
);
|
|
22
|
+
return insertedId;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Update a system instruction by id
|
|
27
|
+
* @param id system instruction id
|
|
28
|
+
* @param data partial system instruction data
|
|
29
|
+
* @returns updated system instruction or null if not found
|
|
30
|
+
*/
|
|
31
|
+
export const updateSystemInstruction = async (
|
|
32
|
+
id: string,
|
|
33
|
+
data: Partial<Omit<SystemInstruction, '_id' | 'createdAt' | 'updatedAt'>>
|
|
34
|
+
): Promise<SystemInstruction | null> => {
|
|
35
|
+
const result = await getSystemInstructionsCollection().findOneAndUpdate(
|
|
36
|
+
{ _id: new ObjectId(id) },
|
|
37
|
+
{ $set: { ...data, updatedAt: new Date() } },
|
|
38
|
+
{ returnDocument: 'after' }
|
|
39
|
+
);
|
|
40
|
+
return result || null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Delete a system instruction by id
|
|
45
|
+
* @param id system instruction id
|
|
46
|
+
* @returns true if deleted, false otherwise
|
|
47
|
+
*/
|
|
48
|
+
export const deleteSystemInstruction = async (id: string): Promise<boolean> => {
|
|
49
|
+
const result = await getSystemInstructionsCollection().deleteOne({ _id: new ObjectId(id) });
|
|
50
|
+
return result.deletedCount > 0;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Activate a system instruction by id, sets isActive to true.
|
|
54
|
+
* Does not check the current instruction state, calling this on an active instruction will do nothing.
|
|
55
|
+
* @param id system instruction id
|
|
56
|
+
* @returns true on success, false otherwise
|
|
57
|
+
*/
|
|
58
|
+
export const activateSystemInstruction = async (id: string): Promise<boolean> => {
|
|
59
|
+
const result = await getSystemInstructionsCollection().findOneAndUpdate(
|
|
60
|
+
{ _id: new ObjectId(id) },
|
|
61
|
+
{ $set: { isActive: true } },
|
|
62
|
+
{ returnDocument: 'after' }
|
|
63
|
+
);
|
|
64
|
+
return Boolean(result);
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Deactivate a system instruction by id, sets isActive to false.
|
|
68
|
+
* Does not check the current instruction state, calling this on a deactivated instruction will do nothing.
|
|
69
|
+
* @param id system instruction id
|
|
70
|
+
* @returns true on success, false otherwise
|
|
71
|
+
*/
|
|
72
|
+
export const deactivateSystemInstruction = async (id: string): Promise<boolean> => {
|
|
73
|
+
const result = await getSystemInstructionsCollection().findOneAndUpdate(
|
|
74
|
+
{ _id: new ObjectId(id) },
|
|
75
|
+
{ $set: { isActive: false } },
|
|
76
|
+
{returnDocument: 'after'}
|
|
77
|
+
);
|
|
78
|
+
return Boolean(result);
|
|
79
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ObjectId } from 'mongodb';
|
|
2
|
+
|
|
3
|
+
import {CityName} from "../utils/types";
|
|
4
|
+
|
|
5
|
+
export type SystemInstruction = {
|
|
6
|
+
_id: ObjectId;
|
|
7
|
+
createdAt: Date;
|
|
8
|
+
updatedAt: Date;
|
|
9
|
+
cityName: CityName;
|
|
10
|
+
instruction: string;
|
|
11
|
+
isActive: boolean;
|
|
12
|
+
tool: string;
|
|
13
|
+
queryType: string;
|
|
14
|
+
tags?: string[]; //no tags implies all wildcard (?)
|
|
15
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { flowMongoSchema } from '../flows.schema';
|
|
2
|
+
|
|
3
|
+
describe('flowMongoSchema', () => {
|
|
4
|
+
it('defines silenceTimeoutSeconds as optional number or null', () => {
|
|
5
|
+
const schema: any = flowMongoSchema;
|
|
6
|
+
|
|
7
|
+
expect(schema.properties).toHaveProperty('silenceTimeoutSeconds');
|
|
8
|
+
expect(schema.properties.silenceTimeoutSeconds.bsonType).toEqual(['number', 'null']);
|
|
9
|
+
expect(schema.required).not.toContain('silenceTimeoutSeconds');
|
|
10
|
+
expect(schema.additionalProperties).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
@@ -8,6 +8,7 @@ export const flowMongoSchema = {
|
|
|
8
8
|
systemInstructions: { bsonType: 'string' },
|
|
9
9
|
initialSentence: { bsonType: 'string' },
|
|
10
10
|
voice: { bsonType: ['string', 'null'] },
|
|
11
|
+
silenceTimeoutSeconds: { bsonType: ['number', 'null'] },
|
|
11
12
|
interactions: {
|
|
12
13
|
bsonType: 'array',
|
|
13
14
|
items: {
|
|
@@ -12,7 +12,7 @@ import { ObjectId } from 'mongodb';
|
|
|
12
12
|
describe('db.phoneNumbers', () => {
|
|
13
13
|
describe('getPhoneDataByPhoneNumber', () => {
|
|
14
14
|
it('return phone number data with flow', async () => {
|
|
15
|
-
const flow = createFlow({ clientId: 'test-client-id' });
|
|
15
|
+
const flow = createFlow({ clientId: 'test-client-id', silenceTimeoutSeconds: 60 });
|
|
16
16
|
const phoneData = createPhoneNumber({ flow_id: flow._id, client_id: 'test-client-id' });
|
|
17
17
|
|
|
18
18
|
await getFlowsCollection().insertOne(flow);
|
|
@@ -28,6 +28,7 @@ describe('db.phoneNumbers', () => {
|
|
|
28
28
|
});
|
|
29
29
|
// Specifically check if the flow was joined correctly
|
|
30
30
|
expect(result?.flow.flowName).toBe(flow.flowName);
|
|
31
|
+
expect(result?.flow.silenceTimeoutSeconds).toBe(60);
|
|
31
32
|
});
|
|
32
33
|
});
|
|
33
34
|
|
|
@@ -10,7 +10,7 @@ describe('sessions', () => {
|
|
|
10
10
|
it('returns session by incoming phone number', async () => {
|
|
11
11
|
const to = '+972500000000';
|
|
12
12
|
const from = '+972540000000';
|
|
13
|
-
const flow = createFlow();
|
|
13
|
+
const flow = createFlow({ silenceTimeoutSeconds: 60 });
|
|
14
14
|
const phoneNumberData = createPhoneNumber({ phone_number: to, flow_id: flow._id });
|
|
15
15
|
const json = { [faker.lorem.word()]: faker.lorem.sentence() };
|
|
16
16
|
|
|
@@ -3,8 +3,9 @@ import { ObjectId } from 'mongodb';
|
|
|
3
3
|
import { faker } from '@faker-js/faker';
|
|
4
4
|
import type {
|
|
5
5
|
DepartmentSubject,
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
} from '../../../municipal/departmentsSubjects/departmentsSubjects.types';
|
|
8
|
+
import {CityName} from "../../../municipal";
|
|
8
9
|
|
|
9
10
|
const VALID_CITIES: CityName[] = ['ashdod', 'maltar', 'billit', 'hashkelon', 'tests'];
|
|
10
11
|
|
|
@@ -2,7 +2,7 @@ import { Factory } from 'fishery';
|
|
|
2
2
|
import { ObjectId } from 'mongodb';
|
|
3
3
|
import { faker } from '@faker-js/faker';
|
|
4
4
|
import type { Ticket } from '../../../municipal/tickets/tickets.types';
|
|
5
|
-
import
|
|
5
|
+
import {CityName} from "../../../municipal";
|
|
6
6
|
|
|
7
7
|
const VALID_CITIES: CityName[] = ['ashdod', 'maltar', 'billit', 'hashkelon', 'tests'];
|
|
8
8
|
|