@talkpilot/core-db 1.3.85 → 1.3.86
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/README.md +1 -0
- package/dist/municipal/muniIssues/index.d.ts +3 -2
- package/dist/municipal/muniIssues/index.d.ts.map +1 -1
- package/dist/municipal/muniIssues/index.js +4 -1
- package/dist/municipal/muniIssues/index.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.constants.d.ts +2 -0
- package/dist/municipal/muniIssues/muniIssues.constants.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.constants.js +8 -1
- package/dist/municipal/muniIssues/muniIssues.constants.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.getters.d.ts +4 -1
- package/dist/municipal/muniIssues/muniIssues.getters.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.getters.js +35 -1
- package/dist/municipal/muniIssues/muniIssues.getters.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.schema.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.schema.js +17 -0
- package/dist/municipal/muniIssues/muniIssues.schema.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.setters.d.ts +3 -1
- package/dist/municipal/muniIssues/muniIssues.setters.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.setters.js +46 -2
- package/dist/municipal/muniIssues/muniIssues.setters.js.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.types.d.ts +22 -2
- package/dist/municipal/muniIssues/muniIssues.types.d.ts.map +1 -1
- package/dist/municipal/muniIssues/muniIssues.utils.d.ts +3 -0
- package/dist/municipal/muniIssues/muniIssues.utils.d.ts.map +1 -0
- package/dist/municipal/muniIssues/muniIssues.utils.js +6 -0
- package/dist/municipal/muniIssues/muniIssues.utils.js.map +1 -0
- package/dist/talkpilot/contextNotes/contextNotes.getters.d.ts +1 -7
- package/dist/talkpilot/contextNotes/contextNotes.getters.d.ts.map +1 -1
- package/dist/talkpilot/contextNotes/contextNotes.getters.js +1 -37
- package/dist/talkpilot/contextNotes/contextNotes.getters.js.map +1 -1
- package/dist/talkpilot/contextNotes/contextNotes.types.d.ts +0 -6
- package/dist/talkpilot/contextNotes/contextNotes.types.d.ts.map +1 -1
- package/dist/talkpilot/flows/flows.schema.d.ts +9 -0
- package/dist/talkpilot/flows/flows.schema.d.ts.map +1 -1
- package/dist/talkpilot/flows/flows.schema.js +7 -0
- package/dist/talkpilot/flows/flows.schema.js.map +1 -1
- package/dist/talkpilot/flows/flows.types.d.ts +3 -0
- package/dist/talkpilot/flows/flows.types.d.ts.map +1 -1
- package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts +4 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.d.ts.map +1 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.js +20 -0
- package/dist/talkpilot/subscriptions/subscriptions.utils.js.map +1 -0
- package/package.json +1 -1
- package/src/municipal/muniIssues/__tests__/muniIssues.getters.spec.ts +87 -0
- package/src/municipal/muniIssues/__tests__/muniIssues.setters.spec.ts +126 -1
- package/src/municipal/muniIssues/__tests__/muniIssues.setup.spec.ts +1 -0
- package/src/municipal/muniIssues/__tests__/muniIssues.utils.spec.ts +17 -0
- package/src/municipal/muniIssues/index.ts +7 -0
- package/src/municipal/muniIssues/muniIssues.constants.ts +9 -0
- package/src/municipal/muniIssues/muniIssues.getters.ts +51 -2
- package/src/municipal/muniIssues/muniIssues.schema.ts +19 -0
- package/src/municipal/muniIssues/muniIssues.setters.ts +66 -3
- package/src/municipal/muniIssues/muniIssues.types.ts +34 -4
- package/src/municipal/muniIssues/muniIssues.utils.ts +6 -0
- package/src/talkpilot/contextNotes/__tests__/contextNotes.getters.spec.ts +0 -141
- package/src/talkpilot/contextNotes/contextNotes.getters.ts +1 -75
- package/src/talkpilot/contextNotes/contextNotes.types.ts +0 -7
- package/src/talkpilot/flows/__tests__/flows.schema.spec.ts +11 -0
- package/src/talkpilot/flows/flows.schema.ts +7 -0
- package/src/talkpilot/flows/flows.types.ts +1 -0
- package/dist/configuration/gptLive.seed.d.ts +0 -2
- package/dist/configuration/gptLive.seed.d.ts.map +0 -1
- package/dist/configuration/gptLive.seed.js +0 -59
- package/dist/configuration/gptLive.seed.js.map +0 -1
- package/dist/talkpilot/clients/clients.quota.constants.d.ts +0 -2
- package/dist/talkpilot/clients/clients.quota.constants.d.ts.map +0 -1
- package/dist/talkpilot/clients/clients.quota.constants.js +0 -5
- package/dist/talkpilot/clients/clients.quota.constants.js.map +0 -1
- package/dist/talkpilot/clients/clients.quota.utils.d.ts +0 -8
- package/dist/talkpilot/clients/clients.quota.utils.d.ts.map +0 -1
- package/dist/talkpilot/clients/clients.quota.utils.js +0 -45
- package/dist/talkpilot/clients/clients.quota.utils.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flows.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/flows/flows.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flows.types.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/flows/flows.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.utils.d.ts","sourceRoot":"","sources":["../../../src/talkpilot/subscriptions/subscriptions.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAA6B,MAAM,UAAU,CAAC;AAE7F,eAAO,MAAM,gBAAgB,GAAI,QAAQ,wBAAwB,KAAG,MAAM,CAAC,YAAY,CAetF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSimpleQuery = void 0;
|
|
4
|
+
const mongodb_1 = require("mongodb");
|
|
5
|
+
const index_1 = require("../index");
|
|
6
|
+
const buildSimpleQuery = (filter) => {
|
|
7
|
+
const query = {};
|
|
8
|
+
if (filter._id) {
|
|
9
|
+
query._id = new mongodb_1.ObjectId(filter._id);
|
|
10
|
+
}
|
|
11
|
+
index_1.simpleFields.forEach((field) => {
|
|
12
|
+
const val = filter[field];
|
|
13
|
+
if (val !== undefined) {
|
|
14
|
+
query[field] = val;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return query;
|
|
18
|
+
};
|
|
19
|
+
exports.buildSimpleQuery = buildSimpleQuery;
|
|
20
|
+
//# sourceMappingURL=subscriptions.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.utils.js","sourceRoot":"","sources":["../../../src/talkpilot/subscriptions/subscriptions.utils.ts"],"names":[],"mappings":";;;AAAA,qCAA2C;AAC3C,oCAA6F;AAEtF,MAAM,gBAAgB,GAAG,CAAC,MAAgC,EAAwB,EAAE;IACzF,MAAM,KAAK,GAAyB,EAAE,CAAC;IAEvC,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,KAAK,CAAC,GAAG,GAAG,IAAI,kBAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,oBAAY,CAAC,OAAO,CAAC,CAAC,KAAkB,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,KAAK,CAAC,KAAK,CAAC,GAAG,GAAU,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAfW,QAAA,gBAAgB,oBAe3B"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ObjectId } from "mongodb";
|
|
2
|
+
import { createMuniIssue, setMuniIssueResponse } from "../muniIssues.setters";
|
|
3
|
+
import {
|
|
4
|
+
countMuniIssuesByClient,
|
|
5
|
+
findMuniIssuesByClient,
|
|
6
|
+
generateMuniIssueId,
|
|
7
|
+
getMuniIssueByIdForClient,
|
|
8
|
+
getMuniIssuesCollection,
|
|
9
|
+
} from "../muniIssues.getters";
|
|
10
|
+
import { createMuniIssueInput } from "../../../test-utils/factories";
|
|
11
|
+
|
|
12
|
+
const CLIENT = "client-a";
|
|
13
|
+
|
|
14
|
+
const createIssue = async (clientId = CLIENT) =>
|
|
15
|
+
(await createMuniIssue(createMuniIssueInput({ clientId }), generateMuniIssueId())).toString();
|
|
16
|
+
|
|
17
|
+
describe("muniIssues getters (complaint tracking)", () => {
|
|
18
|
+
describe("findMuniIssuesByClient / countMuniIssuesByClient", () => {
|
|
19
|
+
it("should return only the client's tracked issues, newest first", async () => {
|
|
20
|
+
const older = await createIssue();
|
|
21
|
+
const newer = await createIssue();
|
|
22
|
+
// Both can land in the same millisecond; make the order explicit.
|
|
23
|
+
await getMuniIssuesCollection().updateOne(
|
|
24
|
+
{ _id: new ObjectId(older) },
|
|
25
|
+
{ $set: { createdAt: new Date(Date.now() - 60_000) } },
|
|
26
|
+
);
|
|
27
|
+
await createIssue("client-b");
|
|
28
|
+
// An issue created before complaint tracking has no status.
|
|
29
|
+
await getMuniIssuesCollection().insertOne({
|
|
30
|
+
...createMuniIssueInput({ clientId: CLIENT }),
|
|
31
|
+
_id: generateMuniIssueId(),
|
|
32
|
+
jira: { key: "CP-legacy", syncStatus: "created" },
|
|
33
|
+
createdAt: new Date(),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const issues = await findMuniIssuesByClient(CLIENT);
|
|
37
|
+
|
|
38
|
+
expect(issues.map((i) => i._id.toString())).toEqual([newer, older]);
|
|
39
|
+
expect(await countMuniIssuesByClient(CLIENT)).toBe(2);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should filter by answered and apply skip/limit", async () => {
|
|
43
|
+
const answered = await createIssue();
|
|
44
|
+
await createIssue();
|
|
45
|
+
await createIssue();
|
|
46
|
+
await setMuniIssueResponse(answered, CLIENT, { status: "resolved", text: "Done" });
|
|
47
|
+
|
|
48
|
+
expect(await countMuniIssuesByClient(CLIENT, { answered: true })).toBe(1);
|
|
49
|
+
expect(await countMuniIssuesByClient(CLIENT, { answered: false })).toBe(2);
|
|
50
|
+
expect(
|
|
51
|
+
(await findMuniIssuesByClient(CLIENT, { answered: true }))[0]._id.toString(),
|
|
52
|
+
).toBe(answered);
|
|
53
|
+
expect(await findMuniIssuesByClient(CLIENT, { skip: 1, limit: 1 })).toHaveLength(1);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should treat a response with only images as answered and a cleared response as waiting", async () => {
|
|
57
|
+
const imagesOnly = await createIssue();
|
|
58
|
+
const cleared = await createIssue();
|
|
59
|
+
const textOnly = await createIssue();
|
|
60
|
+
await setMuniIssueResponse(imagesOnly, CLIENT, {
|
|
61
|
+
status: "resolved",
|
|
62
|
+
text: "",
|
|
63
|
+
imageUrls: ["https://example.com/a.png"],
|
|
64
|
+
});
|
|
65
|
+
await setMuniIssueResponse(cleared, CLIENT, { status: "resolved", text: "Done" });
|
|
66
|
+
await setMuniIssueResponse(cleared, CLIENT, { status: "resolved", text: "", imageUrls: [] });
|
|
67
|
+
await setMuniIssueResponse(textOnly, CLIENT, { status: "resolved", text: "Done" });
|
|
68
|
+
|
|
69
|
+
const answered = await findMuniIssuesByClient(CLIENT, { answered: true });
|
|
70
|
+
const waiting = await findMuniIssuesByClient(CLIENT, { answered: false });
|
|
71
|
+
|
|
72
|
+
expect(answered.map((i) => i._id.toString()).sort()).toEqual([imagesOnly, textOnly].sort());
|
|
73
|
+
expect(waiting.map((i) => i._id.toString())).toEqual([cleared]);
|
|
74
|
+
expect(await countMuniIssuesByClient(CLIENT, { answered: false })).toBe(1);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("getMuniIssueByIdForClient", () => {
|
|
79
|
+
it("should return the issue only for its own client", async () => {
|
|
80
|
+
const id = await createIssue();
|
|
81
|
+
|
|
82
|
+
expect((await getMuniIssueByIdForClient(id, CLIENT))?._id.toString()).toBe(id);
|
|
83
|
+
expect(await getMuniIssueByIdForClient(id, "client-b")).toBeNull();
|
|
84
|
+
expect(await getMuniIssueByIdForClient("not-a-valid-id", CLIENT)).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createMuniIssue,
|
|
3
|
+
setMuniIssueResponse,
|
|
4
|
+
updateMuniIssueStatus,
|
|
5
|
+
} from "../muniIssues.setters";
|
|
2
6
|
import {
|
|
3
7
|
generateMuniIssueId,
|
|
4
8
|
getMuniIssueById,
|
|
@@ -25,6 +29,18 @@ describe("muniIssues setters", () => {
|
|
|
25
29
|
expect(saved?.createdAt).toBeInstanceOf(Date);
|
|
26
30
|
});
|
|
27
31
|
|
|
32
|
+
it("should start the issue as in_review with updatedAt and no response", async () => {
|
|
33
|
+
const insertedId = await createMuniIssue(
|
|
34
|
+
createMuniIssueInput(),
|
|
35
|
+
generateMuniIssueId(),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const saved = await getMuniIssueById(insertedId.toString());
|
|
39
|
+
expect(saved?.status).toBe("in_review");
|
|
40
|
+
expect(saved?.updatedAt).toBeInstanceOf(Date);
|
|
41
|
+
expect(saved?.response).toBeUndefined();
|
|
42
|
+
});
|
|
43
|
+
|
|
28
44
|
it("should default jira.syncStatus to created when not provided", async () => {
|
|
29
45
|
const id = generateMuniIssueId();
|
|
30
46
|
|
|
@@ -91,4 +107,113 @@ describe("muniIssues setters", () => {
|
|
|
91
107
|
expect(await getMuniIssueByJiraKey("CP-nope")).toBeNull();
|
|
92
108
|
});
|
|
93
109
|
});
|
|
110
|
+
|
|
111
|
+
describe("updateMuniIssueStatus", () => {
|
|
112
|
+
it("should change the status of an unanswered issue", async () => {
|
|
113
|
+
const input = createMuniIssueInput();
|
|
114
|
+
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
115
|
+
|
|
116
|
+
expect(await updateMuniIssueStatus(id, input.clientId, "in_progress")).toBe(true);
|
|
117
|
+
expect((await getMuniIssueById(id))?.status).toBe("in_progress");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should not touch another client's issue or a malformed id", async () => {
|
|
121
|
+
const id = (
|
|
122
|
+
await createMuniIssue(createMuniIssueInput(), generateMuniIssueId())
|
|
123
|
+
).toString();
|
|
124
|
+
|
|
125
|
+
expect(await updateMuniIssueStatus(id, "other-client", "resolved")).toBe(false);
|
|
126
|
+
expect(await updateMuniIssueStatus("not-a-valid-id", "any", "resolved")).toBe(false);
|
|
127
|
+
expect((await getMuniIssueById(id))?.status).toBe("in_review");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe("setMuniIssueResponse", () => {
|
|
132
|
+
it("should save the response and status", async () => {
|
|
133
|
+
const input = createMuniIssueInput();
|
|
134
|
+
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
135
|
+
|
|
136
|
+
const saved = await setMuniIssueResponse(id, input.clientId, {
|
|
137
|
+
status: "resolved",
|
|
138
|
+
text: "Fixed",
|
|
139
|
+
imageUrls: ["https://example.com/a.png", "https://example.com/b.png"],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
expect(saved).toBe(true);
|
|
143
|
+
const issue = await getMuniIssueById(id);
|
|
144
|
+
expect(issue?.status).toBe("resolved");
|
|
145
|
+
expect(issue?.response).toMatchObject({
|
|
146
|
+
text: "Fixed",
|
|
147
|
+
imageUrls: ["https://example.com/a.png", "https://example.com/b.png"],
|
|
148
|
+
});
|
|
149
|
+
expect(issue?.response?.createdAt).toBeInstanceOf(Date);
|
|
150
|
+
expect(issue?.response?.updatedAt).toBeUndefined();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should let an answered issue be edited, keeping the first-sent date", async () => {
|
|
154
|
+
const input = createMuniIssueInput();
|
|
155
|
+
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
156
|
+
await setMuniIssueResponse(id, input.clientId, {
|
|
157
|
+
status: "in_review",
|
|
158
|
+
text: "First",
|
|
159
|
+
imageUrls: ["https://example.com/a.png"],
|
|
160
|
+
});
|
|
161
|
+
const firstSentAt = (await getMuniIssueById(id))?.response?.createdAt;
|
|
162
|
+
|
|
163
|
+
expect(
|
|
164
|
+
await setMuniIssueResponse(id, input.clientId, { status: "resolved", text: "Second" }),
|
|
165
|
+
).toBe(true);
|
|
166
|
+
expect(await updateMuniIssueStatus(id, input.clientId, "no_issue_found")).toBe(true);
|
|
167
|
+
|
|
168
|
+
const issue = await getMuniIssueById(id);
|
|
169
|
+
expect(issue?.status).toBe("no_issue_found");
|
|
170
|
+
expect(issue?.response?.text).toBe("Second");
|
|
171
|
+
expect(issue?.response?.imageUrls).toEqual([]);
|
|
172
|
+
expect(issue?.response?.createdAt).toEqual(firstSentAt);
|
|
173
|
+
expect(issue?.response?.updatedAt).toBeInstanceOf(Date);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("should save images without text, and keep a cleared response with its first-sent date", async () => {
|
|
177
|
+
const input = createMuniIssueInput();
|
|
178
|
+
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
179
|
+
|
|
180
|
+
await setMuniIssueResponse(id, input.clientId, {
|
|
181
|
+
status: "resolved",
|
|
182
|
+
text: "",
|
|
183
|
+
imageUrls: ["https://example.com/a.png"],
|
|
184
|
+
});
|
|
185
|
+
const issueWithImage = await getMuniIssueById(id);
|
|
186
|
+
await setMuniIssueResponse(id, input.clientId, { status: "resolved", text: "", imageUrls: [] });
|
|
187
|
+
|
|
188
|
+
const response = (await getMuniIssueById(id))?.response;
|
|
189
|
+
expect(issueWithImage?.response?.imageUrls).toEqual(["https://example.com/a.png"]);
|
|
190
|
+
expect(response?.text).toBe("");
|
|
191
|
+
expect(response?.imageUrls).toEqual([]);
|
|
192
|
+
expect(response?.createdAt).toEqual(issueWithImage?.response?.createdAt);
|
|
193
|
+
expect(response?.updatedAt).toBeInstanceOf(Date);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should store text starting with $ as plain text", async () => {
|
|
197
|
+
const input = createMuniIssueInput();
|
|
198
|
+
const id = (await createMuniIssue(input, generateMuniIssueId())).toString();
|
|
199
|
+
|
|
200
|
+
await setMuniIssueResponse(id, input.clientId, { status: "resolved", text: "$status" });
|
|
201
|
+
|
|
202
|
+
expect((await getMuniIssueById(id))?.response?.text).toBe("$status");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should not touch another client's issue or a malformed id", async () => {
|
|
206
|
+
const id = (
|
|
207
|
+
await createMuniIssue(createMuniIssueInput(), generateMuniIssueId())
|
|
208
|
+
).toString();
|
|
209
|
+
|
|
210
|
+
expect(
|
|
211
|
+
await setMuniIssueResponse(id, "other-client", { status: "resolved", text: "X" }),
|
|
212
|
+
).toBe(false);
|
|
213
|
+
expect(
|
|
214
|
+
await setMuniIssueResponse("not-a-valid-id", "any", { status: "resolved", text: "X" }),
|
|
215
|
+
).toBe(false);
|
|
216
|
+
expect((await getMuniIssueById(id))?.response).toBeUndefined();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
94
219
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { hasMuniIssueResponseContent } from "../muniIssues.utils";
|
|
2
|
+
|
|
3
|
+
describe("hasMuniIssueResponseContent", () => {
|
|
4
|
+
const base = { createdAt: new Date() };
|
|
5
|
+
|
|
6
|
+
it("should be true for text, images, or both", () => {
|
|
7
|
+
expect(hasMuniIssueResponseContent({ ...base, text: "Done" })).toBe(true);
|
|
8
|
+
expect(hasMuniIssueResponseContent({ ...base, text: "", imageUrls: ["a"] })).toBe(true);
|
|
9
|
+
expect(hasMuniIssueResponseContent({ ...base, text: "Done", imageUrls: ["a"] })).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should be false for no response or an empty one", () => {
|
|
13
|
+
expect(hasMuniIssueResponseContent(undefined)).toBe(false);
|
|
14
|
+
expect(hasMuniIssueResponseContent({ ...base, text: "" })).toBe(false);
|
|
15
|
+
expect(hasMuniIssueResponseContent({ ...base, text: "", imageUrls: [] })).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export * from "./muniIssues.getters";
|
|
2
2
|
export * from "./muniIssues.setters";
|
|
3
3
|
export * from "./muniIssues.setup";
|
|
4
|
+
export * from "./muniIssues.utils";
|
|
4
5
|
export {
|
|
5
6
|
MUNI_ISSUES_COLLECTION,
|
|
7
|
+
MUNI_ISSUE_MAX_RESPONSE_IMAGES,
|
|
8
|
+
MUNI_ISSUE_STATUSES,
|
|
6
9
|
MUNI_ISSUE_SYNC_STATUSES,
|
|
7
10
|
MUNI_ISSUE_TEXT_MAX_LENGTH,
|
|
8
11
|
MUNI_ISSUE_NAME_MAX_LENGTH,
|
|
@@ -13,5 +16,9 @@ export type {
|
|
|
13
16
|
MuniIssueContent,
|
|
14
17
|
MuniIssueJira,
|
|
15
18
|
MuniIssueSyncStatus,
|
|
19
|
+
MuniIssueStatus,
|
|
20
|
+
MuniIssueResponse,
|
|
16
21
|
CreateMuniIssueInput,
|
|
22
|
+
SetMuniIssueResponseInput,
|
|
23
|
+
FindMuniIssuesOptions,
|
|
17
24
|
} from "./muniIssues.types";
|
|
@@ -4,6 +4,15 @@ export const MUNI_ISSUES_COLLECTION = "muniIssues";
|
|
|
4
4
|
/** Sync state of the issue's Jira ticket at write time. */
|
|
5
5
|
export const MUNI_ISSUE_SYNC_STATUSES = ["created", "failed"] as const;
|
|
6
6
|
|
|
7
|
+
export const MUNI_ISSUE_STATUSES = [
|
|
8
|
+
"in_review",
|
|
9
|
+
"in_progress",
|
|
10
|
+
"resolved",
|
|
11
|
+
"no_issue_found",
|
|
12
|
+
] as const;
|
|
13
|
+
|
|
14
|
+
export const MUNI_ISSUE_MAX_RESPONSE_IMAGES = 5;
|
|
15
|
+
|
|
7
16
|
/** Max length for the long free-text fields — well above the ~2000-char target. */
|
|
8
17
|
export const MUNI_ISSUE_TEXT_MAX_LENGTH = 5000;
|
|
9
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Collection, ObjectId } from "mongodb";
|
|
1
|
+
import { Collection, Filter, ObjectId } from "mongodb";
|
|
2
2
|
import { getDb } from "../index";
|
|
3
|
-
import { MuniIssue } from "./muniIssues.types";
|
|
3
|
+
import { FindMuniIssuesOptions, MuniIssue } from "./muniIssues.types";
|
|
4
4
|
import { MUNI_ISSUES_COLLECTION } from "./muniIssues.constants";
|
|
5
5
|
|
|
6
6
|
export const getMuniIssuesCollection = (): Collection<MuniIssue> => {
|
|
@@ -22,3 +22,52 @@ export const getMuniIssueByJiraKey = async (
|
|
|
22
22
|
): Promise<MuniIssue | null> => {
|
|
23
23
|
return getMuniIssuesCollection().findOne({ "jira.key": jiraKey });
|
|
24
24
|
};
|
|
25
|
+
|
|
26
|
+
// Answered = the response has text or at least one image; a cleared response object stays in the document.
|
|
27
|
+
const responseHasContent: Filter<MuniIssue>[] = [
|
|
28
|
+
{ "response.text": { $nin: ["", null] } },
|
|
29
|
+
{ "response.imageUrls.0": { $exists: true } },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
// Tracked issues of one client. Issues without a status predate complaint tracking and are excluded.
|
|
33
|
+
const clientIssuesFilter = (
|
|
34
|
+
clientId: string,
|
|
35
|
+
answered?: boolean,
|
|
36
|
+
): Filter<MuniIssue> => ({
|
|
37
|
+
clientId,
|
|
38
|
+
status: { $exists: true },
|
|
39
|
+
...(answered === true && { $or: responseHasContent }),
|
|
40
|
+
...(answered === false && { $nor: responseHasContent }),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const findMuniIssuesByClient = async (
|
|
44
|
+
clientId: string,
|
|
45
|
+
{ answered, skip = 0, limit = 0 }: FindMuniIssuesOptions = {},
|
|
46
|
+
): Promise<MuniIssue[]> => {
|
|
47
|
+
return getMuniIssuesCollection()
|
|
48
|
+
.find(clientIssuesFilter(clientId, answered))
|
|
49
|
+
.sort({ createdAt: -1 })
|
|
50
|
+
.skip(skip)
|
|
51
|
+
.limit(limit)
|
|
52
|
+
.toArray();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const countMuniIssuesByClient = async (
|
|
56
|
+
clientId: string,
|
|
57
|
+
{ answered }: Pick<FindMuniIssuesOptions, "answered"> = {},
|
|
58
|
+
): Promise<number> => {
|
|
59
|
+
return getMuniIssuesCollection().countDocuments(
|
|
60
|
+
clientIssuesFilter(clientId, answered),
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const getMuniIssueByIdForClient = async (
|
|
65
|
+
id: string,
|
|
66
|
+
clientId: string,
|
|
67
|
+
): Promise<MuniIssue | null> => {
|
|
68
|
+
if (!ObjectId.isValid(id)) return null;
|
|
69
|
+
return getMuniIssuesCollection().findOne({
|
|
70
|
+
...clientIssuesFilter(clientId),
|
|
71
|
+
_id: new ObjectId(id),
|
|
72
|
+
});
|
|
73
|
+
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Document, IndexDescription } from "mongodb";
|
|
2
2
|
import {
|
|
3
|
+
MUNI_ISSUE_MAX_RESPONSE_IMAGES,
|
|
4
|
+
MUNI_ISSUE_STATUSES,
|
|
3
5
|
MUNI_ISSUE_SYNC_STATUSES,
|
|
4
6
|
MUNI_ISSUE_TEXT_MAX_LENGTH,
|
|
5
7
|
MUNI_ISSUE_NAME_MAX_LENGTH,
|
|
@@ -55,12 +57,29 @@ export const muniIssuesJsonSchema: Document = {
|
|
|
55
57
|
},
|
|
56
58
|
},
|
|
57
59
|
createdAt: { bsonType: "date" },
|
|
60
|
+
status: { enum: [...MUNI_ISSUE_STATUSES] },
|
|
61
|
+
response: {
|
|
62
|
+
bsonType: "object",
|
|
63
|
+
required: ["text", "createdAt"],
|
|
64
|
+
properties: {
|
|
65
|
+
text: { bsonType: "string", maxLength: MUNI_ISSUE_TEXT_MAX_LENGTH },
|
|
66
|
+
imageUrls: {
|
|
67
|
+
bsonType: "array",
|
|
68
|
+
maxItems: MUNI_ISSUE_MAX_RESPONSE_IMAGES,
|
|
69
|
+
items: { bsonType: "string" },
|
|
70
|
+
},
|
|
71
|
+
createdAt: { bsonType: "date" },
|
|
72
|
+
updatedAt: { bsonType: "date" },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
updatedAt: { bsonType: "date" },
|
|
58
76
|
},
|
|
59
77
|
};
|
|
60
78
|
|
|
61
79
|
export const muniIssuesIndexes: IndexDescription[] = [
|
|
62
80
|
{ key: { callSid: 1 }, name: "callSid_1" },
|
|
63
81
|
{ key: { createdAt: -1 }, name: "createdAt_-1" },
|
|
82
|
+
{ key: { clientId: 1, createdAt: -1 }, name: "clientId_1_createdAt_-1" },
|
|
64
83
|
// Unique: one stored document per Jira ticket, guarding against duplicate writes.
|
|
65
84
|
{ key: { "jira.key": 1 }, name: "jira_key_unique", unique: true },
|
|
66
85
|
];
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import { ObjectId } from "mongodb";
|
|
2
|
-
import {
|
|
1
|
+
import { Filter, ObjectId } from "mongodb";
|
|
2
|
+
import {
|
|
3
|
+
CreateMuniIssueInput,
|
|
4
|
+
MuniIssue,
|
|
5
|
+
MuniIssueStatus,
|
|
6
|
+
SetMuniIssueResponseInput,
|
|
7
|
+
} from "./muniIssues.types";
|
|
3
8
|
import { getMuniIssuesCollection } from "./muniIssues.getters";
|
|
4
9
|
import { ensureMuniIssuesCollectionOnce } from "./muniIssues.setup";
|
|
5
10
|
|
|
@@ -10,6 +15,7 @@ export const createMuniIssue = async (
|
|
|
10
15
|
): Promise<ObjectId> => {
|
|
11
16
|
await ensureMuniIssuesCollectionOnce();
|
|
12
17
|
|
|
18
|
+
const now = new Date();
|
|
13
19
|
const issue: MuniIssue = {
|
|
14
20
|
_id: id,
|
|
15
21
|
...issueData,
|
|
@@ -17,8 +23,65 @@ export const createMuniIssue = async (
|
|
|
17
23
|
...issueData.jira,
|
|
18
24
|
syncStatus: issueData.jira.syncStatus ?? "created",
|
|
19
25
|
},
|
|
20
|
-
|
|
26
|
+
status: "in_review",
|
|
27
|
+
createdAt: now,
|
|
28
|
+
updatedAt: now,
|
|
21
29
|
};
|
|
22
30
|
const { insertedId } = await getMuniIssuesCollection().insertOne(issue);
|
|
23
31
|
return insertedId;
|
|
24
32
|
};
|
|
33
|
+
|
|
34
|
+
// An issue of this client that is tracked (has a status); answered issues stay editable.
|
|
35
|
+
const trackedIssueFilter = (id: string, clientId: string): Filter<MuniIssue> => ({
|
|
36
|
+
_id: new ObjectId(id),
|
|
37
|
+
clientId,
|
|
38
|
+
status: { $exists: true },
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export const updateMuniIssueStatus = async (
|
|
42
|
+
id: string,
|
|
43
|
+
clientId: string,
|
|
44
|
+
status: MuniIssueStatus,
|
|
45
|
+
): Promise<boolean> => {
|
|
46
|
+
if (!ObjectId.isValid(id)) return false;
|
|
47
|
+
await ensureMuniIssuesCollectionOnce();
|
|
48
|
+
|
|
49
|
+
const { matchedCount } = await getMuniIssuesCollection().updateOne(
|
|
50
|
+
trackedIssueFilter(id, clientId),
|
|
51
|
+
{ $set: { status, updatedAt: new Date() } },
|
|
52
|
+
);
|
|
53
|
+
return matchedCount > 0;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const setMuniIssueResponse = async (
|
|
57
|
+
id: string,
|
|
58
|
+
clientId: string,
|
|
59
|
+
{ status, text, imageUrls }: SetMuniIssueResponseInput,
|
|
60
|
+
): Promise<boolean> => {
|
|
61
|
+
if (!ObjectId.isValid(id)) return false;
|
|
62
|
+
await ensureMuniIssuesCollectionOnce();
|
|
63
|
+
|
|
64
|
+
const now = new Date();
|
|
65
|
+
// Pipeline update, so the first-sent date can be read from the stored response.
|
|
66
|
+
// $literal: user text starting with "$" must not be read as a field path.
|
|
67
|
+
const { matchedCount } = await getMuniIssuesCollection().updateOne(
|
|
68
|
+
trackedIssueFilter(id, clientId),
|
|
69
|
+
[
|
|
70
|
+
{
|
|
71
|
+
$set: {
|
|
72
|
+
status: { $literal: status },
|
|
73
|
+
updatedAt: now,
|
|
74
|
+
response: {
|
|
75
|
+
text: { $literal: text },
|
|
76
|
+
imageUrls: { $literal: imageUrls ?? [] },
|
|
77
|
+
createdAt: { $ifNull: ["$response.createdAt", now] },
|
|
78
|
+
updatedAt: {
|
|
79
|
+
$cond: [{ $ifNull: ["$response.createdAt", false] }, now, "$$REMOVE"],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
);
|
|
86
|
+
return matchedCount > 0;
|
|
87
|
+
};
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { ObjectId } from "mongodb";
|
|
2
2
|
|
|
3
3
|
import { CityName } from "../utils/types";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
MUNI_ISSUE_STATUSES,
|
|
6
|
+
MUNI_ISSUE_SYNC_STATUSES,
|
|
7
|
+
} from "./muniIssues.constants";
|
|
5
8
|
|
|
6
9
|
export type MuniIssueSyncStatus = (typeof MUNI_ISSUE_SYNC_STATUSES)[number];
|
|
7
10
|
|
|
11
|
+
export type MuniIssueStatus = (typeof MUNI_ISSUE_STATUSES)[number];
|
|
12
|
+
|
|
13
|
+
export type MuniIssueResponse = {
|
|
14
|
+
text: string;
|
|
15
|
+
imageUrls?: string[];
|
|
16
|
+
createdAt: Date;
|
|
17
|
+
updatedAt?: Date;
|
|
18
|
+
};
|
|
19
|
+
|
|
8
20
|
export type MuniIssueContent = {
|
|
9
21
|
issuerName: string;
|
|
10
22
|
issuerRole: string;
|
|
@@ -25,13 +37,31 @@ export type MuniIssue = {
|
|
|
25
37
|
issueContent: MuniIssueContent;
|
|
26
38
|
jira: MuniIssueJira;
|
|
27
39
|
createdAt: Date;
|
|
40
|
+
// Complaint tracking (CP-1888). Optional: issues created before it have none
|
|
41
|
+
// of these, which is how they are kept out of tracking.
|
|
42
|
+
status?: MuniIssueStatus;
|
|
43
|
+
response?: MuniIssueResponse;
|
|
44
|
+
updatedAt?: Date;
|
|
28
45
|
};
|
|
29
46
|
|
|
30
|
-
// _id/createdAt are set on insert
|
|
31
|
-
// because the issue is only stored after its Jira
|
|
47
|
+
// _id/createdAt/status/updatedAt are set on insert, response only later (setMuniIssueResponse);
|
|
48
|
+
// jira.syncStatus defaults to "created" because the issue is only stored after its Jira
|
|
49
|
+
// ticket exists (CP-1115).
|
|
32
50
|
export type CreateMuniIssueInput = Omit<
|
|
33
51
|
MuniIssue,
|
|
34
|
-
"_id" | "createdAt" | "jira"
|
|
52
|
+
"_id" | "createdAt" | "jira" | "status" | "response" | "updatedAt"
|
|
35
53
|
> & {
|
|
36
54
|
jira: { key: string; syncStatus?: MuniIssueSyncStatus };
|
|
37
55
|
};
|
|
56
|
+
|
|
57
|
+
export type SetMuniIssueResponseInput = {
|
|
58
|
+
status: MuniIssueStatus;
|
|
59
|
+
text: string;
|
|
60
|
+
imageUrls?: string[];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type FindMuniIssuesOptions = {
|
|
64
|
+
answered?: boolean;
|
|
65
|
+
skip?: number;
|
|
66
|
+
limit?: number;
|
|
67
|
+
};
|