Skip to content

Commit d3202c8

Browse files
authored
Merge pull request #387 from AppQuality/develop
Release 20250519
2 parents 9b52abd + c3c9fb1 commit d3202c8

6 files changed

Lines changed: 215 additions & 14 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"author": "",
2222
"license": "ISC",
2323
"dependencies": {
24-
"@appquality/tryber-database": "^0.44.0",
24+
"@appquality/tryber-database": "^0.44.6",
2525
"@appquality/wp-auth": "^1.0.7",
2626
"@googlemaps/google-maps-services-js": "^3.3.7",
2727
"@sendgrid/mail": "^7.6.0",

src/reference/openapi.yml

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10736,12 +10736,6 @@ components:
1073610736
- 0
1073710737
productType: 0
1073810738
notes: string
10739-
required:
10740-
- project
10741-
- testType
10742-
- title
10743-
- startDate
10744-
- deviceList
1074510739
properties:
1074610740
project:
1074710741
type: integer
@@ -10775,14 +10769,14 @@ components:
1077510769
type: array
1077610770
items:
1077710771
type: object
10778-
required:
10779-
- role
10780-
- user
1078110772
properties:
1078210773
role:
1078310774
type: integer
1078410775
user:
1078510776
type: integer
10777+
required:
10778+
- role
10779+
- user
1078610780
description:
1078710781
type: string
1078810782
productLink:
@@ -10818,6 +10812,37 @@ components:
1081810812
type: integer
1081910813
notes:
1082010814
type: string
10815+
additionals:
10816+
x-stoplight:
10817+
id: prsjf310wgcw1
10818+
type: array
10819+
items:
10820+
x-stoplight:
10821+
id: 05yh361c4m134
10822+
allOf:
10823+
- type: object
10824+
x-stoplight:
10825+
id: ob87gktp597p8
10826+
properties:
10827+
showInStats:
10828+
type: boolean
10829+
x-stoplight:
10830+
id: h3ll753yh9e2x
10831+
- $ref: '#/components/schemas/CampaignAdditionalField'
10832+
bugTypes:
10833+
type: array
10834+
x-stoplight:
10835+
id: b3tzoarrt5ir1
10836+
items:
10837+
x-stoplight:
10838+
id: grb3h65cr8pmi
10839+
type: number
10840+
required:
10841+
- project
10842+
- testType
10843+
- title
10844+
- startDate
10845+
- deviceList
1082110846
FiscalBirthCity:
1082210847
title: FiscalBirthCity
1082310848
oneOf:

src/routes/dossiers/_post/creation.spec.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const baseRequest = {
1717

1818
describe("Route POST /dossiers", () => {
1919
beforeAll(async () => {
20+
await tryber.seeds().bug_types();
2021
await tryber.tables.CampaignPhase.do().insert([
2122
{ id: 1, name: "Test Phase", type_id: 1 },
2223
]);
@@ -116,6 +117,7 @@ describe("Route POST /dossiers", () => {
116117
await tryber.tables.CampaignDossierDataBrowsers.do().delete();
117118
await tryber.tables.CampaignDossierDataLanguages.do().delete();
118119
await tryber.tables.CampaignDossierDataCountries.do().delete();
120+
await tryber.tables.WpAppqCampaignAdditionalFields.do().delete();
119121
});
120122

121123
it("Should create a campaign", async () => {
@@ -274,6 +276,126 @@ describe("Route POST /dossiers", () => {
274276
expect(campaign).toHaveProperty("close_date", "2021-08-20 14:15:22");
275277
});
276278

279+
it("Should create a campaign with the specified additional fields", async () => {
280+
const response = await request(app)
281+
.post("/dossiers")
282+
.set("authorization", "Bearer admin")
283+
.send({
284+
...baseRequest,
285+
additionals: [
286+
{
287+
name: "Regex Field",
288+
slug: "regex-field",
289+
error: "Regex error",
290+
type: "text",
291+
regex: "^[a-zA-Z0-9]+$",
292+
},
293+
{
294+
name: "Select Field",
295+
slug: "select-field",
296+
error: "Select error",
297+
type: "select",
298+
showInStats: true,
299+
options: ["Option 1", "Option 2"],
300+
},
301+
],
302+
});
303+
expect(response.status).toBe(201);
304+
expect(response.body).toHaveProperty("id");
305+
const id = response.body.id;
306+
307+
const fields = await tryber.tables.WpAppqCampaignAdditionalFields.do()
308+
.select()
309+
.where("cp_id", id);
310+
311+
expect(fields).toHaveLength(2);
312+
expect(fields).toEqual(
313+
expect.arrayContaining([
314+
expect.objectContaining({
315+
cp_id: id,
316+
title: "Regex Field",
317+
slug: "regex-field",
318+
type: "regex",
319+
validation: "^[a-zA-Z0-9]+$",
320+
error_message: "Regex error",
321+
stats: 0,
322+
}),
323+
expect.objectContaining({
324+
cp_id: id,
325+
title: "Select Field",
326+
slug: "select-field",
327+
type: "select",
328+
validation: "Option 1;Option 2",
329+
error_message: "Select error",
330+
stats: 1,
331+
}),
332+
])
333+
);
334+
});
335+
336+
it("Should create a campaign with the specified bug types", async () => {
337+
const response = await request(app)
338+
.post("/dossiers")
339+
.set("authorization", "Bearer admin")
340+
.send({
341+
...baseRequest,
342+
bugTypes: [1, 2, 3],
343+
});
344+
expect(response.status).toBe(201);
345+
expect(response.body).toHaveProperty("id");
346+
const id = response.body.id;
347+
348+
const bugTypes = await tryber.tables.WpAppqAdditionalBugTypes.do()
349+
.select()
350+
.where("campaign_id", id);
351+
352+
expect(bugTypes).toHaveLength(3);
353+
expect(bugTypes).toEqual(
354+
expect.arrayContaining([
355+
expect.objectContaining({
356+
bug_type_id: 1,
357+
}),
358+
expect.objectContaining({
359+
bug_type_id: 2,
360+
}),
361+
expect.objectContaining({
362+
bug_type_id: 3,
363+
}),
364+
])
365+
);
366+
});
367+
368+
it("Should create a campaign with default bug types if no specific bug types are selected", async () => {
369+
const response = await request(app)
370+
.post("/dossiers")
371+
.set("authorization", "Bearer admin")
372+
.send({
373+
...baseRequest,
374+
});
375+
expect(response.status).toBe(201);
376+
expect(response.body).toHaveProperty("id");
377+
const id = response.body.id;
378+
379+
const bugTypes = await tryber.tables.WpAppqAdditionalBugTypes.do()
380+
.select()
381+
.where("campaign_id", id);
382+
383+
expect(bugTypes).toHaveLength(0);
384+
});
385+
386+
it("Should throw an error if invalid bugtype is sent", async () => {
387+
const response = await request(app)
388+
.post("/dossiers")
389+
.set("authorization", "Bearer admin")
390+
.send({
391+
...baseRequest,
392+
bugTypes: [100],
393+
});
394+
expect(response.status).toBe(406);
395+
expect(response.body).toHaveProperty("id");
396+
const id = response.body.id;
397+
});
398+
277399
it("Should create a campaign with the end date as start date + 7 if left unspecified", async () => {
278400
const response = await request(app)
279401
.post("/dossiers")

src/routes/dossiers/_post/index.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export default class PostDossiers extends UserRoute<{
4444
this.setError(406, new OpenapiError("Invalid roles submitted"));
4545
return false;
4646
}
47+
if (await this.invalidBugTypesSubmitted()) {
48+
this.setError(406, new OpenapiError("Invalid bug types submitted"));
49+
return false;
50+
}
4751
if (!(await this.projectExists())) {
4852
this.setError(400, new OpenapiError("Project does not exist"));
4953
return false;
@@ -104,6 +108,17 @@ export default class PostDossiers extends UserRoute<{
104108
return false;
105109
}
106110

111+
private async invalidBugTypesSubmitted() {
112+
const { bugTypes } = this.getBody();
113+
if (!bugTypes || !bugTypes.length) return false;
114+
const bugTypeIds = [...new Set(bugTypes)];
115+
const bugTypesExist = await tryber.tables.WpAppqEvdBugType.do()
116+
.select()
117+
.whereIn("id", bugTypeIds);
118+
if (bugTypesExist.length !== bugTypeIds.length) return true;
119+
return false;
120+
}
121+
107122
private async projectExists(): Promise<boolean> {
108123
const { project: projectId } = this.getBody();
109124
const project = await tryber.tables.WpAppqProject.do()
@@ -292,6 +307,9 @@ export default class PostDossiers extends UserRoute<{
292307
await this.createCampaignMeta(campaignId);
293308
}
294309

310+
await this.createAdditionals(campaignId);
311+
await this.setBugTypes(campaignId);
312+
295313
const dossier = await tryber.tables.CampaignDossierData.do()
296314
.insert({
297315
campaign_id: campaignId,
@@ -353,6 +371,38 @@ export default class PostDossiers extends UserRoute<{
353371
return campaignId;
354372
}
355373

374+
private async createAdditionals(campaignId: number) {
375+
const { additionals } = this.getBody();
376+
if (!additionals || !additionals.length) return;
377+
378+
await tryber.tables.WpAppqCampaignAdditionalFields.do().insert(
379+
additionals.map((additional) => ({
380+
cp_id: campaignId,
381+
type: additional.type === "text" ? "regex" : "select",
382+
slug: additional.slug,
383+
title: additional.name,
384+
validation:
385+
additional.type === "text"
386+
? additional.regex
387+
: additional.options.join(";"),
388+
error_message: additional.error,
389+
stats: additional.showInStats ? 1 : 0,
390+
}))
391+
);
392+
}
393+
394+
private async setBugTypes(campaignId: number) {
395+
const { bugTypes } = this.getBody();
396+
if (!bugTypes || !bugTypes.length) return;
397+
398+
await tryber.tables.WpAppqAdditionalBugTypes.do().insert(
399+
bugTypes.map((bugType) => ({
400+
campaign_id: campaignId,
401+
bug_type_id: bugType,
402+
}))
403+
);
404+
}
405+
356406
private async linkRolesToCampaign(campaignId: number) {
357407
const roles = this.getBody().roles;
358408
if (!roles?.length) return;

src/schema.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,10 @@ export interface components {
830830
browsers?: number[];
831831
productType?: number;
832832
notes?: string;
833+
additionals?: ({
834+
showInStats?: boolean;
835+
} & components["schemas"]["CampaignAdditionalField"])[];
836+
bugTypes?: number[];
833837
};
834838
/** FiscalBirthCity */
835839
FiscalBirthCity:

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
"@babel/parser" "^7.22.5"
2929
"@babel/traverse" "^7.22.5"
3030

31-
"@appquality/tryber-database@^0.44.0":
32-
version "0.44.0"
33-
resolved "https://registry.npmjs.org/@appquality/tryber-database/-/tryber-database-0.44.0.tgz#cac013386883c3bdc6940abdee69ac534d248cf7"
34-
integrity sha512-5jUmbWu71phpASv19WLbO9dRHdgEiuVDyw9ECAaOS5o8GMZJLLD1G+O4Ev3vSQ335BphWsvubw9y8nVJUH+GQA==
31+
"@appquality/tryber-database@^0.44.6":
32+
version "0.44.6"
33+
resolved "https://registry.npmjs.org/@appquality/tryber-database/-/tryber-database-0.44.6.tgz#7791c4f351c2e10ac26f1c297f2297356391c848"
34+
integrity sha512-a0hnYnAjyEiygjsujg1O3DDO7uEBA3RsEBCpcrz2Ltwkjwbbi2OzqOtmW9cn58scYC10U3rst/pWz9NZvcBCXA==
3535
dependencies:
3636
better-sqlite3 "^8.1.0"
3737
knex "^2.5.1"

0 commit comments

Comments
 (0)