From 9d0109cce511224a9f6864247fa8f16f967fd536 Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Fri, 23 Jan 2026 15:41:04 +0100 Subject: [PATCH 01/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index e5dc569a7..fee3628b7 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -3981,6 +3981,85 @@ paths: required: true schema: type: string + '/campaigns/{campaign}/finance/attachments': + parameters: + - schema: + type: string + name: campaign + in: path + required: true + - schema: + type: string + name: campaign + in: path + required: true + post: + summary: Your POST endpoint + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + attachments: + type: array + x-stoplight: + id: 8emd735q3eekn + items: + x-stoplight: + id: ma1yyks3wpuez + type: object + required: + - url + - name + - mime_type + properties: + url: + type: string + x-stoplight: + id: ysk2k5gez9d5h + name: + type: string + x-stoplight: + id: prluokcfrw7p9 + mime_type: + type: string + x-stoplight: + id: l7f6z5ngj01uy + '403': + $ref: '#/components/responses/NotAuthorized' + '500': + description: Internal Server Error + operationId: post-campaigns-campaign-finance-attachments + x-stoplight: + id: 0ucra88nj3skb + security: + - JWT: [] + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + attachment: + x-stoplight: + id: loo9qp15yg7er + oneOf: + - type: string + x-stoplight: + id: 1y0da4vjut50n + format: binary + - type: array + x-stoplight: + id: 567eldf6sv5mh + items: + x-stoplight: + id: ykrxebcilk657 + type: string + format: binary '/campaigns/{campaign}/forms': get: description: '' From 777fcceb6d3f1d3859e3501cb869bf7742d6d9ba Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Tue, 27 Jan 2026 15:48:45 +0100 Subject: [PATCH 02/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index fee3628b7..22e303b2a 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -4029,6 +4029,26 @@ paths: type: string x-stoplight: id: l7f6z5ngj01uy + failed: + type: array + x-stoplight: + id: 7ddxgc7abxz39 + items: + x-stoplight: + id: 5r1ivzdsjci00 + type: object + required: + - name + - path + properties: + name: + type: string + x-stoplight: + id: cwjl6g75vg2lr + path: + type: string + x-stoplight: + id: s3fuamuxbq1wn '403': $ref: '#/components/responses/NotAuthorized' '500': From 11e9c13d9a8a5307c0a786a4316ccfe7ad234af5 Mon Sep 17 00:00:00 2001 From: ZecD Date: Tue, 27 Jan 2026 16:48:05 +0100 Subject: [PATCH 03/31] feat: add POST /campaigns/{campaign}/finance/attachments route and update OpenAPI schema --- src/reference/openapi.yml | 20 +-- .../finance/attachment/_post/index.spec.ts | 98 +++++++++++++ .../finance/attachment/_post/index.ts | 132 ++++++++++++++++++ src/schema.ts | 43 ++++++ 4 files changed, 275 insertions(+), 18 deletions(-) create mode 100644 src/routes/campaigns/campaignId/finance/attachment/_post/index.spec.ts create mode 100644 src/routes/campaigns/campaignId/finance/attachment/_post/index.ts diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index 22e303b2a..1ea5c9b11 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -4006,11 +4006,7 @@ paths: properties: attachments: type: array - x-stoplight: - id: 8emd735q3eekn items: - x-stoplight: - id: ma1yyks3wpuez type: object required: - url @@ -4019,23 +4015,15 @@ paths: properties: url: type: string - x-stoplight: - id: ysk2k5gez9d5h + name: type: string - x-stoplight: - id: prluokcfrw7p9 mime_type: type: string - x-stoplight: - id: l7f6z5ngj01uy failed: type: array - x-stoplight: - id: 7ddxgc7abxz39 + items: - x-stoplight: - id: 5r1ivzdsjci00 type: object required: - name @@ -4043,12 +4031,8 @@ paths: properties: name: type: string - x-stoplight: - id: cwjl6g75vg2lr path: type: string - x-stoplight: - id: s3fuamuxbq1wn '403': $ref: '#/components/responses/NotAuthorized' '500': diff --git a/src/routes/campaigns/campaignId/finance/attachment/_post/index.spec.ts b/src/routes/campaigns/campaignId/finance/attachment/_post/index.spec.ts new file mode 100644 index 000000000..0d3a10b36 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/attachment/_post/index.spec.ts @@ -0,0 +1,98 @@ +import app from "@src/app"; +import { tryber } from "@src/features/database"; +import upload from "@src/features/upload"; +import request from "supertest"; + +jest.mock("@src/features/upload"); + +const profile = { + id: 1, + wp_user_id: 1, + email: "tester@example.com", + employment_id: 1, + education_id: 1, +}; +const wpUser = { + ID: 1, + user_login: "tester", + user_email: "tester@example.com", + user_pass: "pass", +}; +const campaign = { + id: 1, + title: "Test Campaign", + customer_title: "Test Campaign", + start_date: "2020-01-01", + end_date: "2020-01-01", + pm_id: 1, + page_manual_id: 0, + page_preview_id: 0, + platform_id: 1, + customer_id: 1, + project_id: 1, +}; + +const campaign2 = { + ...campaign, + id: 2, +}; + +describe("Route POST /campaigns/{campaignId}/finance/attachments", () => { + beforeAll(async () => { + (upload as jest.Mock).mockImplementation( + ({ key, bucket }: { bucket: string; key: string }) => { + return `https://s3.amazonaws.com/${bucket}/${key}`; + } + ); + await tryber.tables.WpUsers.do().insert(wpUser); + await tryber.tables.WpAppqEvdProfile.do().insert(profile); + await tryber.tables.WpAppqEvdCampaign.do().insert([campaign, campaign2]); + }); + + afterAll(async () => { + await tryber.tables.WpUsers.do().delete(); + await tryber.tables.WpAppqEvdProfile.do().delete(); + await tryber.tables.WpAppqEvdCampaign.do().delete(); + }); + + it("Should answer 403 if not logged in", async () => { + const response = await request(app).post( + "/campaigns/1/finance/attachments" + ); + expect(response.status).toBe(403); + }); + + it("Should answer 200 and mark as failed if try to send file as .bat, .sh and .exe", async () => { + const mockFileBuffer = Buffer.from("some data"); + + const response = await request(app) + .post("/campaigns/1/finance/attachments") + .attach("media", mockFileBuffer, "void.bat") + .attach("media", mockFileBuffer, "image.png") + .attach("media", mockFileBuffer, "void.sh") + .attach("media", mockFileBuffer, "void.exe") + .set("authorization", 'Bearer tester olp {"appq_campaign":[1]}'); + + expect(response.status).toBe(200); + expect(response.body).toHaveProperty("failed", [ + { path: "INVALID_FILE_EXTENSION", name: "void.bat" }, + { path: "INVALID_FILE_EXTENSION", name: "void.sh" }, + { path: "INVALID_FILE_EXTENSION", name: "void.exe" }, + ]); + }); + + it("Should answer 200 and mark as failed if try to send an oversized file", async () => { + process.env.MAX_FILE_SIZE = "100"; + const mockFileBuffer = Buffer.alloc(101); + + const response = await request(app) + .post("/campaigns/1/finance/attachments") + .attach("media", mockFileBuffer, "oversized.png") + .set("authorization", 'Bearer tester olp {"appq_campaign":[1]}'); + + expect(response.status).toBe(200); + expect(response.body).toHaveProperty("failed", [ + { path: "FILE_TOO_BIG", name: "oversized.png" }, + ]); + }); +}); diff --git a/src/routes/campaigns/campaignId/finance/attachment/_post/index.ts b/src/routes/campaigns/campaignId/finance/attachment/_post/index.ts new file mode 100644 index 000000000..08586a79a --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/attachment/_post/index.ts @@ -0,0 +1,132 @@ +/** OPENAPI-CLASS: post-campaigns-campaign-finance-attachments */ +import upload from "@src/features/upload"; +import path from "path"; +import busboyMapper from "@src/features/busboyMapper"; +import CampaignRoute from "@src/features/routes/CampaignRoute"; +import OpenapiError from "@src/features/OpenapiError"; +import debugMessage from "@src/features/debugMessage"; + +interface InvalidMedia { + name: string; + path: string; +} + +interface UploadSuccess { + files: { name: string; mime_type: string; path: string }[]; + failed: InvalidMedia[]; +} + +interface UploadError { + element: string; + id: number; + message: string; +} + +export default class SingleCampaignRoute extends CampaignRoute<{ + response: StoplightOperations["post-campaigns-campaign-finance-attachments"]["responses"]["200"]["content"]["application/json"]; + body: StoplightOperations["post-campaigns-campaign-finance-attachments"]["requestBody"]["content"]["multipart/form-data"]; + parameters: StoplightOperations["post-campaigns-campaign-finance-attachments"]["parameters"]["path"]; +}> { + protected async filter(): Promise { + if (!(await super.filter())) return false; + if (!this.hasAccessToCampaign(this.cp_id)) { + this.setError(403, new OpenapiError("Access denied")); + return false; + } + return true; + } + + protected async prepare(): Promise { + try { + const result = await this.uploadAttachmentFiles(); + + if ("message" in result) { + throw new OpenapiError(result.message); + } + + return this.setSuccess(200, { + attachments: result.files.map((file) => ({ + url: file.path, + name: file.name, + mime_type: file.mime_type, + })), + failed: result.failed, + }); + } catch (err) { + debugMessage(err); + this.setError( + (err as OpenapiError).status_code || 500, + err as OpenapiError + ); + } + } + + protected getKey({ + filename, + extension, + }: { + filename: string; + extension: string; + }): string { + return `${ + process.env.FINANCE_ATTACHMENTS_FOLDER || "finance-attachments" + }/CP${this.cp_id}/${filename}_${new Date().getTime()}${extension}`; + } + + protected isAcceptableFile(file: { name: string }): boolean { + return ![".bat", ".sh", ".exe"].includes( + path.extname(file.name).toLowerCase() + ); + } + + private async uploadAttachmentFiles(): Promise { + try { + const { valid, invalid } = await busboyMapper( + this.configuration.request, + (file) => { + if (!this.isAcceptableFile(file)) { + return "INVALID_FILE_EXTENSION"; + } + return false; + } + ); + + return { + files: await this.uploadFiles(valid), + failed: invalid.map((fail) => ({ + name: fail.name, + path: fail.errorCode, + })), + }; + } catch (err) { + return { + element: "media-upload", + id: 0, + message: err instanceof Error ? err.message : "Unknown error", + }; + } + } + + private async uploadFiles( + files: Media[] + ): Promise<{ name: string; mime_type: string; path: string }[]> { + let uploadedFiles = []; + for (const media of files) { + const uploadedPath = await upload({ + bucket: process.env.MEDIA_BUCKET || "", + key: this.getKey({ + filename: path.basename(media.name, path.extname(media.name)), + extension: path.extname(media.name), + }), + file: media, + }); + + uploadedFiles.push({ + name: media.name, + mime_type: media.mimeType, + path: uploadedPath.toString(), + }); + } + return uploadedFiles; + } +} diff --git a/src/schema.ts b/src/schema.ts index 05530f136..9f5413273 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -146,6 +146,14 @@ export interface paths { }; }; }; + "/campaigns/{campaign}/finance/attachments": { + post: operations["post-campaigns-campaign-finance-attachments"]; + parameters: { + path: { + campaign: string; + }; + }; + }; "/campaigns/{campaign}/forms": { get: operations["get-campaigns-campaign-forms"]; parameters: { @@ -2113,6 +2121,41 @@ export interface operations { 404: components["responses"]["NotFound"]; }; }; + "post-campaigns-campaign-finance-attachments": { + parameters: { + path: { + campaign: string; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": { + attachments?: { + url: string; + name: string; + mime_type: string; + }[]; + failed?: { + name: string; + path: string; + }[]; + }; + }; + }; + 403: components["responses"]["NotAuthorized"]; + /** Internal Server Error */ + 500: unknown; + }; + requestBody: { + content: { + "multipart/form-data": { + attachment?: string | string[]; + }; + }; + }; + }; "get-campaigns-campaign-forms": { parameters: { path: { From 39443dab1dfd673d2859746db9aef4ff9f21f58f Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 16:25:46 +0100 Subject: [PATCH 04/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index e5dc569a7..a785d2206 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13199,6 +13199,48 @@ paths: - jotformId - testerQuestionId description: '' + '/campaigns/{campaign}/finance/supplier': + parameters: + - schema: + type: string + name: campaign + in: path + required: true + post: + summary: POST a new supplier + tags: [] + responses: + '201': + description: Created + '403': + $ref: '#/components/responses/NotAuthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + operationId: post-campaigns-campaign-finance-supplier + x-stoplight: + id: j17dlfvjwluu7 + description: Create a new campaign supplier + requestBody: + content: + application/json: + schema: + type: object + required: + - name + - created_by + properties: + name: + type: string + x-stoplight: + id: bzvnmo26hda42 + created_by: + type: integer + x-stoplight: + id: 5ri3rzkppb17t + security: + - JWT: [] servers: - url: 'https://api.app-quality.com' tags: From c2577d2de6262c029658aba3da96574b2d771b89 Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 16:57:23 +0100 Subject: [PATCH 05/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index a785d2206..c3361481a 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13229,16 +13229,11 @@ paths: type: object required: - name - - created_by properties: name: type: string x-stoplight: id: bzvnmo26hda42 - created_by: - type: integer - x-stoplight: - id: 5ri3rzkppb17t security: - JWT: [] servers: From c075223c6c51e07593637ee02736dae748e9b213 Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 16:58:42 +0100 Subject: [PATCH 06/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index c3361481a..99ab1bb63 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13234,6 +13234,10 @@ paths: type: string x-stoplight: id: bzvnmo26hda42 + examples: + Example 1: + value: + name: Respondent security: - JWT: [] servers: From ee47019428829c1a4a5570cd8e6de5f9100f410e Mon Sep 17 00:00:00 2001 From: Kariamos Date: Wed, 28 Jan 2026 17:03:24 +0100 Subject: [PATCH 07/31] feat: add endpoint to create a new campaign supplier --- src/schema.ts | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/schema.ts b/src/schema.ts index 05530f136..c62e4cee8 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -796,6 +796,15 @@ export interface paths { }; }; }; + "/campaigns/{campaign}/finance/supplier": { + /** Create a new campaign supplier */ + post: operations["post-campaigns-campaign-finance-supplier"]; + parameters: { + path: { + campaign: string; + }; + }; + }; } export interface components { @@ -809,6 +818,7 @@ export interface components { }; Agreement: { expirationDate: string; + /** @default false */ isTokenBased?: boolean; note?: string; startDate: string; @@ -888,6 +898,7 @@ export interface components { applied?: boolean; /** @description If bugform is deactivated is a boolean else contains URLs to bugforms for each languages */ bugform_link?: boolean | components["schemas"]["TranslatablePage"]; + /** @default 0 */ csm_effort?: number; customerCanViewReviewing?: boolean; customer_title?: string; @@ -910,7 +921,9 @@ export interface components { public?: boolean; status?: boolean; titleRule?: boolean; + /** @default 0 */ tokens?: number; + /** @default 0 */ ux_effort?: number; visibility?: { freeSpots?: number; @@ -2984,15 +2997,20 @@ export interface operations { }; } & { autoApply?: number; + /** @default 0 */ autoApprove?: number; bugLanguage?: components["schemas"]["BugLang"]; hasBugForm?: number; hasBugParade?: number; /** @enum {string} */ pageVersion?: "v1" | "v2"; + /** @default 0 */ skipPagesAndTasks?: number; } & { - /** @enum {undefined} */ + /** + * @default 0 + * @enum {undefined} + */ notify_everyone?: 0 | 1; /** @example 1 */ ux_notify?: number; @@ -3013,6 +3031,7 @@ export interface operations { content: { "application/json": { autoApply: number; + /** @default 0 */ autoApprove: number; browsers?: { id: number; @@ -3035,6 +3054,7 @@ export interface operations { name: string; }[]; deviceRequirements?: string; + /** @default false */ hasPlan?: boolean; /** Format: date-time */ endDate: string; @@ -3121,6 +3141,7 @@ export interface operations { content: { "application/json": components["schemas"]["DossierCreationData"] & { autoApply?: number; + /** @default 0 */ autoApprove?: number; bugLanguage?: components["schemas"]["BugLang"] | boolean; hasBugParade?: number; @@ -5458,6 +5479,29 @@ export interface operations { }; }; }; + /** Create a new campaign supplier */ + "post-campaigns-campaign-finance-supplier": { + parameters: { + path: { + campaign: string; + }; + }; + responses: { + /** Created */ + 201: unknown; + 403: components["responses"]["NotAuthorized"]; + 404: components["responses"]["NotFound"]; + /** Internal Server Error */ + 500: unknown; + }; + requestBody: { + content: { + "application/json": { + name: string; + }; + }; + }; + }; } export interface external {} From 09288fd7abafe907f0e52a660aafe5df03b02596 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Wed, 28 Jan 2026 17:03:39 +0100 Subject: [PATCH 08/31] feat: implement POST route for campaign finance supplier with validation --- .../finance/supplier/_post/index.spec.ts | 144 ++++++++++++++++++ .../finance/supplier/_post/index.ts | 59 +++++++ 2 files changed, 203 insertions(+) create mode 100644 src/routes/campaigns/campaignId/finance/supplier/_post/index.spec.ts create mode 100644 src/routes/campaigns/campaignId/finance/supplier/_post/index.ts diff --git a/src/routes/campaigns/campaignId/finance/supplier/_post/index.spec.ts b/src/routes/campaigns/campaignId/finance/supplier/_post/index.spec.ts new file mode 100644 index 000000000..0fabdaaf6 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/supplier/_post/index.spec.ts @@ -0,0 +1,144 @@ +import request from "supertest"; +import app from "@src/app"; +import { tryber } from "@src/features/database"; + +describe("POST /campaigns/campaignId/finance/supplier", () => { + beforeAll(async () => { + await tryber.tables.WpAppqEvdProfile.do().insert([ + { + id: 1, + name: "John", + surname: "Doe", + wp_user_id: 1, + email: "", + employment_id: 1, + education_id: 1, + }, + { + id: 2, + name: "John", + surname: "Doe", + wp_user_id: 2, + email: "", + employment_id: 1, + education_id: 1, + }, + ]); + await tryber.tables.WpUsers.do().insert([{ ID: 1 }, { ID: 2 }]); + await tryber.tables.WpAppqEvdCampaign.do().insert({ + id: 1, + platform_id: 1, + start_date: "2020-01-01", + end_date: "2020-01-01", + title: "This is the title", + page_preview_id: 1, + page_manual_id: 1, + customer_id: 1, + pm_id: 1, + project_id: 1, + customer_title: "", + }); + }); + + beforeEach(async () => { + await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().insert([ + { + id: 1, + name: "Supplier 1", + created_by: 1, + created_on: "2024-01-01 10:00:00", + }, + ]); + }); + + afterEach(async () => { + await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().delete(); + }); + + afterAll(async () => { + await tryber.tables.WpAppqEvdCampaign.do().delete(); + await tryber.tables.WpUsers.do().delete(); + await tryber.tables.WpAppqEvdProfile.do().delete(); + }); + + describe("Not enough permissions", () => { + it("Should return 403 if logged out", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "New Supplier" }); + expect(response.status).toBe(403); + }); + + it("Should return 403 if logged in as not admin user", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "New Supplier" }) + .set("Authorization", "Bearer tester"); + expect(response.status).toBe(403); + }); + + it("Should return 403 if no access to the campaign", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "New Supplier" }) + .set("Authorization", 'Bearer tester"'); + expect(response.status).toBe(403); + }); + }); + + describe("Enough permissions - admin", () => { + it("Should return 200 if logged in as admin", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "New Supplier" }) + .set("Authorization", "Bearer admin"); + expect(response.status).toBe(201); + }); + + it("Should add new finance supplier", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "New Supplier" }) + .set("Authorization", "Bearer admin"); + expect(response.status).toBe(201); + }); + it("Should not add existing supplier", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "Supplier 1" }) + .set("Authorization", "Bearer admin"); + expect(response.status).toBe(400); + }); + + it("Should not add supplier with empty name", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: " " }) + .set("Authorization", "Bearer admin"); + expect(response.status).toBe(400); + expect(response.body).toEqual( + expect.objectContaining({ + message: "Supplier name should not be empty", + }) + ); + }); + }); + + describe("Enough permissions - olp", () => { + it("Should add supplier ", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "New Supplier" }) + .set("Authorization", 'Bearer tester olp {"appq_campaign":[1]}'); + expect(response.status).toBe(201); + }); + + it("Should not add existing supplier", async () => { + const response = await request(app) + .post("/campaigns/1/finance/supplier") + .send({ name: "Supplier 1" }) + .set("Authorization", 'Bearer tester olp {"appq_campaign":[1]}'); + expect(response.status).toBe(400); + }); + }); +}); diff --git a/src/routes/campaigns/campaignId/finance/supplier/_post/index.ts b/src/routes/campaigns/campaignId/finance/supplier/_post/index.ts new file mode 100644 index 000000000..031568347 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/supplier/_post/index.ts @@ -0,0 +1,59 @@ +/** OPENAPI-CLASS: post-campaigns-campaign-finance-supplier */ + +import CampaignRoute from "@src/features/routes/CampaignRoute"; +import { tryber } from "@src/features/database"; +import OpenapiError from "@src/features/OpenapiError"; + +export default class SupplierRoute extends CampaignRoute<{ + response: StoplightOperations["post-campaigns-campaign-finance-supplier"]["responses"]["201"]; + parameters: StoplightOperations["post-campaigns-campaign-finance-supplier"]["parameters"]["path"]; + body: StoplightOperations["post-campaigns-campaign-finance-supplier"]["requestBody"]["content"]["application/json"]; +}> { + protected async filter(): Promise { + if (!(await super.filter())) return false; + + if (!this.hasAccessToCampaign(this.cp_id)) { + this.setError(403, new OpenapiError("Access denied")); + + return false; + } + + if (this.getBody().name.trim() === "") { + this.setError(400, new OpenapiError("Supplier name should not be empty")); + return false; + } + + return true; + } + + protected async prepare(): Promise { + if (await this.checkSupplierExists(this.getBody().name)) { + return this.setError(400, new OpenapiError("Supplier already exists")); + } + + try { + await this.createNewSupplier(this.getBody().name); + return this.setSuccess(201, {}); + } catch (e) { + console.error("Error creating new supplier: ", e); + return this.setError( + 500, + new OpenapiError("Error creating new supplier") + ); + } + } + + private async createNewSupplier(name: string): Promise { + await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().insert({ + name, + created_by: this.getTesterId(), + }); + } + + private async checkSupplierExists(name: string): Promise { + const supplier = await tryber.tables.WpAppqCampaignOtherCostsSupplier.do() + .where({ name }) + .first(); + return supplier !== undefined; + } +} From 7e105f7be2445cd07d909d61d1b08a03ebe46a97 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 11:52:36 +0100 Subject: [PATCH 09/31] fix: update @appquality/tryber-database version to 0.46.17 in package.json and package-lock.json --- package-lock.json | 74 ++++++++++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index f31d9f1d1..d6091ad94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@appquality/tryber-database": "^0.46.11", + "@appquality/tryber-database": "^0.46.17", "@appquality/wp-auth": "^1.0.7", "@aws-crypto/sha256-js": "^5.2.0", "@aws-sdk/hash-node": "^3.374.0", @@ -108,9 +108,9 @@ } }, "node_modules/@appquality/tryber-database": { - "version": "0.46.11", - "resolved": "https://registry.npmjs.org/@appquality/tryber-database/-/tryber-database-0.46.11.tgz", - "integrity": "sha512-mec9oRm+ojlVoVqQqHZfVRbJIPSmZs163oWYsRXH+Ab7XESeWqlAySjg4hpVl0WZXr5wnH+AgJ2vt4d2LFhzpw==", + "version": "0.46.17", + "resolved": "https://registry.npmjs.org/@appquality/tryber-database/-/tryber-database-0.46.17.tgz", + "integrity": "sha512-pipi0ypxbkSqkGD69yEx/6M8yYkd3uCevS0Gw7tc97MieSgsGU75X/CIBF7Adr04xbk1tPMLIS7uZ9Q+nJ10vQ==", "license": "ISC", "dependencies": { "better-sqlite3": "^12.5.0", @@ -468,7 +468,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1004,6 +1003,7 @@ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1028,6 +1028,7 @@ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1082,6 +1083,7 @@ "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -1097,6 +1099,7 @@ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=12.22" }, @@ -1111,7 +1114,8 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -2841,7 +2845,6 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" @@ -3385,7 +3388,6 @@ "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -3584,7 +3586,6 @@ "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -3745,7 +3746,8 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/abbrev": { "version": "3.0.1", @@ -3776,7 +3778,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3790,6 +3791,7 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -4447,7 +4449,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.14.7" } @@ -4834,7 +4835,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5658,7 +5658,8 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/deepmerge": { "version": "4.3.1", @@ -5810,6 +5811,7 @@ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -6044,6 +6046,7 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -6142,6 +6145,7 @@ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -6159,6 +6163,7 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -6178,6 +6183,7 @@ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -6221,6 +6227,7 @@ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -6234,6 +6241,7 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -6277,6 +6285,7 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6671,7 +6680,8 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-safe-stringify": { "version": "2.1.1", @@ -6724,6 +6734,7 @@ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -6807,6 +6818,7 @@ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -6824,6 +6836,7 @@ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -6838,7 +6851,8 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/floating-point-regex": { "version": "0.1.0", @@ -7194,6 +7208,7 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -7235,6 +7250,7 @@ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -7596,6 +7612,7 @@ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -7899,6 +7916,7 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -8111,7 +8129,6 @@ "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^28.1.3", "@jest/types": "^28.1.3", @@ -9209,7 +9226,8 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -9229,7 +9247,8 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json5": { "version": "2.2.3", @@ -9309,6 +9328,7 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -9446,6 +9466,7 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -9485,6 +9506,7 @@ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -10763,6 +10785,7 @@ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -10797,6 +10820,7 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -10855,6 +10879,7 @@ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -11194,6 +11219,7 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8.0" } @@ -11617,6 +11643,7 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=4" } @@ -12816,7 +12843,8 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/through2": { "version": "2.0.5", @@ -12899,7 +12927,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13091,7 +13118,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -13697,6 +13723,7 @@ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -13720,6 +13747,7 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -13746,7 +13774,6 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14111,6 +14138,7 @@ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 8618d0745..1203c771a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "author": "", "license": "ISC", "dependencies": { - "@appquality/tryber-database": "^0.46.11", + "@appquality/tryber-database": "^0.46.17", "@appquality/wp-auth": "^1.0.7", "@aws-crypto/sha256-js": "^5.2.0", "@aws-sdk/hash-node": "^3.374.0", From e3163d560baa7f3ec7d9bdf2395d44df33e1513d Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Thu, 29 Jan 2026 12:12:14 +0100 Subject: [PATCH 10/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index e5dc569a7..358ff9ac0 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13199,6 +13199,56 @@ paths: - jotformId - testerQuestionId description: '' + '/campaigns/{campaign}/finance/type': + parameters: + - schema: + type: string + name: campaign + in: path + required: true + get: + summary: GET types + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + required: + - items + properties: + items: + type: array + x-stoplight: + id: d7f0e5l5qrx6o + items: + x-stoplight: + id: r1p9rcymebjpu + type: object + properties: + name: + type: string + x-stoplight: + id: y0keeoutvijjh + examples: + Example 1: + value: + items: + - name: Recruiting + - name: Survey + '403': + $ref: '#/components/responses/NotAuthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Shared Response + operationId: get-campaigns-campaign-finance-type + x-stoplight: + id: 02e8ns5xdhecm + security: + - JWT: [] servers: - url: 'https://api.app-quality.com' tags: From d08d1231115c501c3dba9bb15bcfd2e87e38d469 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 12:14:44 +0100 Subject: [PATCH 11/31] fix: update @appquality/tryber-database dependency to version 0.46.17 --- package-lock.json | 74 ++++++++++++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index f31d9f1d1..d6091ad94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@appquality/tryber-database": "^0.46.11", + "@appquality/tryber-database": "^0.46.17", "@appquality/wp-auth": "^1.0.7", "@aws-crypto/sha256-js": "^5.2.0", "@aws-sdk/hash-node": "^3.374.0", @@ -108,9 +108,9 @@ } }, "node_modules/@appquality/tryber-database": { - "version": "0.46.11", - "resolved": "https://registry.npmjs.org/@appquality/tryber-database/-/tryber-database-0.46.11.tgz", - "integrity": "sha512-mec9oRm+ojlVoVqQqHZfVRbJIPSmZs163oWYsRXH+Ab7XESeWqlAySjg4hpVl0WZXr5wnH+AgJ2vt4d2LFhzpw==", + "version": "0.46.17", + "resolved": "https://registry.npmjs.org/@appquality/tryber-database/-/tryber-database-0.46.17.tgz", + "integrity": "sha512-pipi0ypxbkSqkGD69yEx/6M8yYkd3uCevS0Gw7tc97MieSgsGU75X/CIBF7Adr04xbk1tPMLIS7uZ9Q+nJ10vQ==", "license": "ISC", "dependencies": { "better-sqlite3": "^12.5.0", @@ -468,7 +468,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1004,6 +1003,7 @@ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1028,6 +1028,7 @@ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1082,6 +1083,7 @@ "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -1097,6 +1099,7 @@ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=12.22" }, @@ -1111,7 +1114,8 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -2841,7 +2845,6 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" @@ -3385,7 +3388,6 @@ "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -3584,7 +3586,6 @@ "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -3745,7 +3746,8 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/abbrev": { "version": "3.0.1", @@ -3776,7 +3778,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3790,6 +3791,7 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -4447,7 +4449,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.14.7" } @@ -4834,7 +4835,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5658,7 +5658,8 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/deepmerge": { "version": "4.3.1", @@ -5810,6 +5811,7 @@ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -6044,6 +6046,7 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -6142,6 +6145,7 @@ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -6159,6 +6163,7 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -6178,6 +6183,7 @@ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -6221,6 +6227,7 @@ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -6234,6 +6241,7 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -6277,6 +6285,7 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -6671,7 +6680,8 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-safe-stringify": { "version": "2.1.1", @@ -6724,6 +6734,7 @@ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -6807,6 +6818,7 @@ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -6824,6 +6836,7 @@ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -6838,7 +6851,8 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/floating-point-regex": { "version": "0.1.0", @@ -7194,6 +7208,7 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -7235,6 +7250,7 @@ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -7596,6 +7612,7 @@ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -7899,6 +7916,7 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -8111,7 +8129,6 @@ "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^28.1.3", "@jest/types": "^28.1.3", @@ -9209,7 +9226,8 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -9229,7 +9247,8 @@ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/json5": { "version": "2.2.3", @@ -9309,6 +9328,7 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -9446,6 +9466,7 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -9485,6 +9506,7 @@ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -10763,6 +10785,7 @@ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -10797,6 +10820,7 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -10855,6 +10879,7 @@ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -11194,6 +11219,7 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8.0" } @@ -11617,6 +11643,7 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=4" } @@ -12816,7 +12843,8 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/through2": { "version": "2.0.5", @@ -12899,7 +12927,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13091,7 +13118,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -13697,6 +13723,7 @@ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -13720,6 +13747,7 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -13746,7 +13774,6 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14111,6 +14138,7 @@ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 8618d0745..1203c771a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "author": "", "license": "ISC", "dependencies": { - "@appquality/tryber-database": "^0.46.11", + "@appquality/tryber-database": "^0.46.17", "@appquality/wp-auth": "^1.0.7", "@aws-crypto/sha256-js": "^5.2.0", "@aws-sdk/hash-node": "^3.374.0", From f84104460e949d7048e333df533d0a8f9d7efdf7 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 12:15:05 +0100 Subject: [PATCH 12/31] feat: add finance type endpoint for campaigns --- src/schema.ts | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/schema.ts b/src/schema.ts index 05530f136..ebc110b71 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -796,6 +796,14 @@ export interface paths { }; }; }; + "/campaigns/{campaign}/finance/type": { + get: operations["get-campaigns-campaign-finance-type"]; + parameters: { + path: { + campaign: string; + }; + }; + }; } export interface components { @@ -809,6 +817,7 @@ export interface components { }; Agreement: { expirationDate: string; + /** @default false */ isTokenBased?: boolean; note?: string; startDate: string; @@ -888,6 +897,7 @@ export interface components { applied?: boolean; /** @description If bugform is deactivated is a boolean else contains URLs to bugforms for each languages */ bugform_link?: boolean | components["schemas"]["TranslatablePage"]; + /** @default 0 */ csm_effort?: number; customerCanViewReviewing?: boolean; customer_title?: string; @@ -910,7 +920,9 @@ export interface components { public?: boolean; status?: boolean; titleRule?: boolean; + /** @default 0 */ tokens?: number; + /** @default 0 */ ux_effort?: number; visibility?: { freeSpots?: number; @@ -2984,15 +2996,20 @@ export interface operations { }; } & { autoApply?: number; + /** @default 0 */ autoApprove?: number; bugLanguage?: components["schemas"]["BugLang"]; hasBugForm?: number; hasBugParade?: number; /** @enum {string} */ pageVersion?: "v1" | "v2"; + /** @default 0 */ skipPagesAndTasks?: number; } & { - /** @enum {undefined} */ + /** + * @default 0 + * @enum {undefined} + */ notify_everyone?: 0 | 1; /** @example 1 */ ux_notify?: number; @@ -3013,6 +3030,7 @@ export interface operations { content: { "application/json": { autoApply: number; + /** @default 0 */ autoApprove: number; browsers?: { id: number; @@ -3035,6 +3053,7 @@ export interface operations { name: string; }[]; deviceRequirements?: string; + /** @default false */ hasPlan?: boolean; /** Format: date-time */ endDate: string; @@ -3121,6 +3140,7 @@ export interface operations { content: { "application/json": components["schemas"]["DossierCreationData"] & { autoApply?: number; + /** @default 0 */ autoApprove?: number; bugLanguage?: components["schemas"]["BugLang"] | boolean; hasBugParade?: number; @@ -5458,6 +5478,29 @@ export interface operations { }; }; }; + "get-campaigns-campaign-finance-type": { + parameters: { + path: { + campaign: string; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": { + items: { + name?: string; + }[]; + }; + }; + }; + 403: components["responses"]["NotAuthorized"]; + 404: components["responses"]["NotFound"]; + /** Shared Response */ + 500: unknown; + }; + }; } export interface external {} From 3b762a792901195f3c58880359249eaa3066b2fc Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 12:44:38 +0100 Subject: [PATCH 13/31] feat: implement finance type retrieval for campaigns --- .../finance/type/_get/index.spec.ts | 115 ++++++++++++++++++ .../campaignId/finance/type/_get/index.ts | 31 +++++ 2 files changed, 146 insertions(+) create mode 100644 src/routes/campaigns/campaignId/finance/type/_get/index.spec.ts create mode 100644 src/routes/campaigns/campaignId/finance/type/_get/index.ts diff --git a/src/routes/campaigns/campaignId/finance/type/_get/index.spec.ts b/src/routes/campaigns/campaignId/finance/type/_get/index.spec.ts new file mode 100644 index 000000000..3c9580e41 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/type/_get/index.spec.ts @@ -0,0 +1,115 @@ +import request from "supertest"; +import app from "@src/app"; +import { tryber } from "@src/features/database"; + +describe("GET /campaigns/campaignId/finance/type", () => { + beforeAll(async () => { + await tryber.tables.WpAppqEvdProfile.do().insert([ + { + id: 1, + name: "John", + surname: "Doe", + wp_user_id: 1, + email: "", + employment_id: 1, + education_id: 1, + }, + ]); + await tryber.tables.WpUsers.do().insert({ ID: 1 }); + await tryber.tables.WpAppqEvdCampaign.do().insert({ + id: 1, + platform_id: 1, + start_date: "2020-01-01", + end_date: "2020-01-01", + title: "This is the title", + page_preview_id: 1, + page_manual_id: 1, + customer_id: 1, + pm_id: 1, + project_id: 1, + customer_title: "", + }); + await tryber.tables.WpAppqCampaignOtherCostsType.do().insert([ + { + id: 1, + name: "Type 1", + }, + { + id: 2, + name: "Type 2", + }, + ]); + }); + + afterAll(async () => { + await tryber.tables.WpAppqCampaignOtherCostsType.do().delete(); + await tryber.tables.WpAppqEvdCampaign.do().delete(); + await tryber.tables.WpUsers.do().delete(); + await tryber.tables.WpAppqEvdProfile.do().delete(); + }); + + it("Should return 403 if logged out", async () => { + const response = await request(app).get("/campaigns/1/finance/type"); + expect(response.status).toBe(403); + }); + + it("Should return 403 if logged in as not admin user", async () => { + const response = await request(app) + .get("/campaigns/1/finance/type") + .set("Authorization", "Bearer tester"); + expect(response.status).toBe(403); + }); + + it("Should return 403 if no access to the campaign", async () => { + const response = await request(app) + .get("/campaigns/1/finance/type") + .set("Authorization", 'Bearer tester"'); + expect(response.status).toBe(403); + }); + + it("Should return 200 if logged in as admin", async () => { + const response = await request(app) + .get("/campaigns/1/finance/type") + .set("Authorization", "Bearer admin"); + expect(response.status).toBe(200); + }); + + it("Should return finance types - admin", async () => { + const response = await request(app) + .get("/campaigns/1/finance/type") + .set("Authorization", "Bearer admin"); + expect(response.body).toEqual( + expect.objectContaining({ + items: expect.arrayContaining([ + expect.objectContaining({ + name: "Type 1", + }), + expect.objectContaining({ + name: "Type 2", + }), + ]), + }) + ); + expect(response.body.items).toHaveLength(2); + }); + + it("Should return types - olp permissions", async () => { + const response = await request(app) + .get("/campaigns/1/finance/type") + .set("Authorization", 'Bearer tester olp {"appq_campaign":[1]}'); + expect(response.status).toBe(200); + expect(response.body).toEqual( + expect.objectContaining({ + items: expect.arrayContaining([ + expect.objectContaining({ + name: "Type 1", + }), + expect.objectContaining({ + name: "Type 2", + }), + ]), + }) + ); + expect(response.body.items).toHaveLength(2); + }); +}); diff --git a/src/routes/campaigns/campaignId/finance/type/_get/index.ts b/src/routes/campaigns/campaignId/finance/type/_get/index.ts new file mode 100644 index 000000000..484995ac4 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/type/_get/index.ts @@ -0,0 +1,31 @@ +/** OPENAPI-CLASS: get-campaigns-campaign-finance-type */ + +import CampaignRoute from "@src/features/routes/CampaignRoute"; +import { tryber } from "@src/features/database"; +import OpenapiError from "@src/features/OpenapiError"; + +export default class TypeRoute extends CampaignRoute<{ + response: StoplightOperations["get-campaigns-campaign-finance-type"]["responses"]["200"]["content"]["application/json"]; + parameters: StoplightOperations["get-campaigns-campaign-finance-type"]["parameters"]["path"]; +}> { + protected async filter(): Promise { + if (!(await super.filter())) return false; + + if (!this.hasAccessToCampaign(this.cp_id)) { + this.setError(403, new OpenapiError("Access denied")); + + return false; + } + return true; + } + + protected async prepare(): Promise { + const types = await this.getTypes(); + + return this.setSuccess(200, { items: types }); + } + + private async getTypes() { + return await tryber.tables.WpAppqCampaignOtherCostsType.do().select("name"); + } +} From 40752e0bc7b7058d7622aba997a01d4ceb9c2bcf Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 10:12:29 +0100 Subject: [PATCH 14/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 105 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index 568641bb7..10471d637 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -3981,6 +3981,65 @@ paths: required: true schema: type: string + '/campaigns/{campaign}/finance/supplier': + get: + description: Get all suppliers for finance + operationId: get-campaigns-cid-finance-supplier + parameters: [] + responses: + '200': + content: + application/json: + examples: + Example 2: + value: + id: 1 + name: Respondent + created_on: '2026-01-01' + created_by: 32 + schema: + type: object + required: + - id + - name + properties: + id: + type: number + x-stoplight: + id: ctt8sbti2xlsa + name: + type: string + x-stoplight: + id: p42d6s7ngpjtz + created_on: + type: string + x-stoplight: + id: cx6fszbvodyk6 + created_by: + type: integer + x-stoplight: + id: 9avtyf2lbwksr + description: OK + '403': + $ref: '#/components/responses/NotAuthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + description: Internal Server Error + security: + - JWT: [] + summary: Get all suppliers + tags: + - Campaign + x-stoplight: + id: hx8pmv3nzamq0 + parameters: + - description: A campaign id + in: path + name: campaign + required: true + schema: + type: string '/campaigns/{campaign}/finance/attachments': parameters: - schema: @@ -13282,6 +13341,52 @@ paths: - jotformId - testerQuestionId description: '' + '/campaigns/{campaign}/finance/suppliers': + get: + description: Get all finance suppliers + operationId: get-campaigns-cid-finance-supplier + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + required: + - id + - name + properties: + id: + type: number + x-stoplight: + id: hhr19m5dfxjtt + name: + type: string + x-stoplight: + id: tyq39dn4ard6q + created_at: + type: string + x-stoplight: + id: fdxd59qz1usvz + created_by: + type: integer + x-stoplight: + id: dkqscj2zlqbq1 + examples: + Example 1: + value: + id: 1 + name: Respondent + created_at: '2026-01-01' + created_by: 10 + '400': + description: Bad Request + '403': + description: Forbidden + '500': + description: Internal Server Error + security: + - JWT: [] '/campaigns/{campaign}/finance/type': parameters: - schema: From 67ef756420b75fba24e98e028efdb266eae388e2 Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 10:41:30 +0100 Subject: [PATCH 15/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 57 ++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index 10471d637..ffd97d8bb 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13344,7 +13344,7 @@ paths: '/campaigns/{campaign}/finance/suppliers': get: description: Get all finance suppliers - operationId: get-campaigns-cid-finance-supplier + operationId: get-campaigns-campaign-finance-supplier responses: '200': description: OK @@ -13353,32 +13353,44 @@ paths: schema: type: object required: - - id - - name + - items properties: - id: - type: number + items: + type: array x-stoplight: id: hhr19m5dfxjtt - name: - type: string - x-stoplight: - id: tyq39dn4ard6q - created_at: - type: string - x-stoplight: - id: fdxd59qz1usvz - created_by: - type: integer - x-stoplight: - id: dkqscj2zlqbq1 + items: + x-stoplight: + id: ihcfe7bywmrjs + type: object + required: + - name + - id + properties: + name: + type: string + x-stoplight: + id: 08yzm5eu8tl1h + created_at: + type: string + x-stoplight: + id: w0fmflgc090ff + created_by: + type: integer + x-stoplight: + id: gcs2p8mvl32gc + id: + type: integer + x-stoplight: + id: 3lwwkv3h1vsun examples: - Example 1: + Example 2: value: - id: 1 - name: Respondent - created_at: '2026-01-01' - created_by: 10 + items: + - id: 1 + name: Respondent + created_at: '2026-01-01' + created_by: 10 '400': description: Bad Request '403': @@ -13387,6 +13399,7 @@ paths: description: Internal Server Error security: - JWT: [] + summary: Get finance supplier '/campaigns/{campaign}/finance/type': parameters: - schema: From adbc425d1fe1a8710a7d4654d5d8f963ceefec34 Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 10:46:07 +0100 Subject: [PATCH 16/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index ffd97d8bb..b51e74dd3 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13400,6 +13400,12 @@ paths: security: - JWT: [] summary: Get finance supplier + parameters: + - schema: + type: string + name: campaign + in: path + required: true '/campaigns/{campaign}/finance/type': parameters: - schema: From 933e544d7c65df61a726d350b18ef25a4f7792c5 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Wed, 28 Jan 2026 11:15:39 +0100 Subject: [PATCH 17/31] feat: add finance suppliers endpoints for campaigns --- src/schema.ts | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/schema.ts b/src/schema.ts index e65ad0843..87d90c684 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -154,6 +154,16 @@ export interface paths { }; }; }; + "/campaigns/{campaign}/finance/supplier": { + /** Get all suppliers for finance */ + get: operations["get-campaigns-cid-finance-supplier"]; + parameters: { + path: { + /** A campaign id */ + campaign: string; + }; + }; + }; "/campaigns/{campaign}/forms": { get: operations["get-campaigns-campaign-forms"]; parameters: { @@ -812,6 +822,15 @@ export interface paths { }; }; }; + "/campaigns/{campaign}/finance/suppliers": { + /** Get all finance suppliers */ + get: operations["get-campaigns-campaign-finance-supplier"]; + parameters: { + path: { + campaign: string; + }; + }; + }; } export interface components { @@ -2168,6 +2187,32 @@ export interface operations { }; }; }; + /** Get all suppliers for finance */ + "get-campaigns-cid-finance-supplier": { + parameters: { + path: { + /** A campaign id */ + campaign: string; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": { + id: number; + name: string; + created_on?: string; + created_by?: number; + }; + }; + }; + 403: components["responses"]["NotAuthorized"]; + 404: components["responses"]["NotFound"]; + /** Internal Server Error */ + 500: unknown; + }; + }; "get-campaigns-campaign-forms": { parameters: { path: { @@ -5544,6 +5589,35 @@ export interface operations { 500: unknown; }; }; + /** Get all finance suppliers */ + "get-campaigns-campaign-finance-supplier": { + parameters: { + path: { + campaign: string; + }; + }; + responses: { + /** OK */ + 200: { + content: { + "application/json": { + items: { + name: string; + created_at?: string; + created_by?: number; + id: number; + }[]; + }; + }; + }; + /** Bad Request */ + 400: unknown; + /** Forbidden */ + 403: unknown; + /** Internal Server Error */ + 500: unknown; + }; + }; } export interface external {} From 2e1205715b5980eb1b5186177a5ea171b8890e7a Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Wed, 28 Jan 2026 11:41:31 +0100 Subject: [PATCH 18/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 86 +++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index b51e74dd3..dd35be6db 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -3981,51 +3981,65 @@ paths: required: true schema: type: string - '/campaigns/{campaign}/finance/supplier': - get: - description: Get all suppliers for finance - operationId: get-campaigns-cid-finance-supplier - parameters: [] + '/campaigns/{campaign}/finance/attachments': + parameters: + - schema: + type: string + name: campaign + in: path + required: true + - schema: + type: string + name: campaign + in: path + required: true + post: + summary: Your POST endpoint + tags: [] responses: '200': + description: OK content: application/json: - examples: - Example 2: - value: - id: 1 - name: Respondent - created_on: '2026-01-01' - created_by: 32 schema: type: object - required: - - id - - name properties: - id: - type: number - x-stoplight: - id: ctt8sbti2xlsa - name: - type: string - x-stoplight: - id: p42d6s7ngpjtz - created_on: - type: string - x-stoplight: - id: cx6fszbvodyk6 - created_by: - type: integer - x-stoplight: - id: 9avtyf2lbwksr - description: OK + attachments: + type: array + items: + type: object + required: + - url + - name + - mime_type + properties: + url: + type: string + + name: + type: string + mime_type: + type: string + failed: + type: array + + items: + type: object + required: + - name + - path + properties: + name: + type: string + path: + type: string '403': $ref: '#/components/responses/NotAuthorized' - '404': - $ref: '#/components/responses/NotFound' '500': description: Internal Server Error + operationId: post-campaigns-campaign-finance-attachments + x-stoplight: + id: 0ucra88nj3skb security: - JWT: [] summary: Get all suppliers @@ -13341,7 +13355,7 @@ paths: - jotformId - testerQuestionId description: '' - '/campaigns/{campaign}/finance/suppliers': + '/campaigns/{campaign}/finance/supplier': get: description: Get all finance suppliers operationId: get-campaigns-campaign-finance-supplier @@ -13400,6 +13414,8 @@ paths: security: - JWT: [] summary: Get finance supplier + x-stoplight: + id: tlziygldrfder parameters: - schema: type: string From d1f9a38148156a5a8470a7a6e98b064eeb571e4e Mon Sep 17 00:00:00 2001 From: Kariamos Date: Wed, 28 Jan 2026 11:45:36 +0100 Subject: [PATCH 19/31] refactor: update finance suppliers endpoint and remove duplicated operation --- src/schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schema.ts b/src/schema.ts index 87d90c684..a6df456fd 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -822,7 +822,7 @@ export interface paths { }; }; }; - "/campaigns/{campaign}/finance/suppliers": { + "/campaigns/{campaign}/finance/supplier": { /** Get all finance suppliers */ get: operations["get-campaigns-campaign-finance-supplier"]; parameters: { From c9de03090150941fae72ec296c0c22f8ddfb03ec Mon Sep 17 00:00:00 2001 From: Kariamos Date: Wed, 28 Jan 2026 12:02:35 +0100 Subject: [PATCH 20/31] feat: implement finance suppliers endpoint for campaigns --- .../finance/supplier/_get/index.spec.ts | 133 ++++++++++++++++++ .../campaignId/finance/supplier/_get/index.ts | 45 ++++++ 2 files changed, 178 insertions(+) create mode 100644 src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts create mode 100644 src/routes/campaigns/campaignId/finance/supplier/_get/index.ts diff --git a/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts b/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts new file mode 100644 index 000000000..da5e4c384 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts @@ -0,0 +1,133 @@ +import request from "supertest"; +import app from "@src/app"; +import { tryber } from "@src/features/database"; + +describe("GET /campaigns/campaignId/finance/supplier", () => { + beforeAll(async () => { + await tryber.tables.WpAppqEvdProfile.do().insert([ + { + id: 1, + name: "John", + surname: "Doe", + wp_user_id: 1, + email: "", + employment_id: 1, + education_id: 1, + }, + { + id: 2, + name: "John", + surname: "Doe", + wp_user_id: 2, + email: "", + employment_id: 1, + education_id: 1, + }, + ]); + await tryber.tables.WpUsers.do().insert([{ ID: 1 }, { ID: 2 }]); + await tryber.tables.WpAppqEvdCampaign.do().insert({ + id: 1, + platform_id: 1, + start_date: "2020-01-01", + end_date: "2020-01-01", + title: "This is the title", + page_preview_id: 1, + page_manual_id: 1, + customer_id: 1, + pm_id: 1, + project_id: 1, + customer_title: "", + }); + await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().insert([ + { + id: 1, + name: "Supplier 1", + created_by: 1, + created_on: "2024-01-01 10:00:00", + }, + { + id: 2, + name: "Supplier 2", + created_by: 2, + created_on: "2024-01-02 11:00:00", + }, + ]); + }); + + it("Should return 403 if logged out", async () => { + const response = await request(app).get("/campaigns/1/finance/supplier"); + expect(response.status).toBe(403); + }); + + it("Should return 403 if logged in as not admin user", async () => { + const response = await request(app) + .get("/campaigns/1/finance/supplier") + .set("Authorization", "Bearer tester"); + expect(response.status).toBe(403); + }); + + it("Should return 403 if no access to the campaign", async () => { + const response = await request(app) + .get("/campaigns/1/finance/supplier") + .set("Authorization", 'Bearer tester"'); + expect(response.status).toBe(403); + }); + + it("Should return 200 if logged in as admin", async () => { + const response = await request(app) + .get("/campaigns/1/finance/supplier") + .set("Authorization", "Bearer admin"); + expect(response.status).toBe(200); + }); + + it("Should return finance suppliers", async () => { + const response = await request(app) + .get("/campaigns/1/finance/supplier") + .set("Authorization", "Bearer admin"); + expect(response.body).toEqual( + expect.objectContaining({ + items: expect.arrayContaining([ + expect.objectContaining({ + id: 1, + name: "Supplier 1", + created_by: 1, + created_on: "2024-01-01 10:00:00", + }), + expect.objectContaining({ + id: 2, + name: "Supplier 2", + created_by: 2, + created_on: "2024-01-02 11:00:00", + }), + ]), + }) + ); + expect(response.body.items).toHaveLength(2); + }); + + it("Should return suppliers with olp permissions", async () => { + const response = await request(app) + .get("/campaigns/1/finance/supplier") + .set("Authorization", 'Bearer tester olp {"appq_campaign":[1]}'); + expect(response.status).toBe(200); + expect(response.body).toEqual( + expect.objectContaining({ + items: expect.arrayContaining([ + expect.objectContaining({ + id: 1, + name: "Supplier 1", + created_by: 1, + created_on: "2024-01-01 10:00:00", + }), + expect.objectContaining({ + id: 2, + name: "Supplier 2", + created_by: 2, + created_on: "2024-01-02 11:00:00", + }), + ]), + }) + ); + expect(response.body.items).toHaveLength(2); + }); +}); diff --git a/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts b/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts new file mode 100644 index 000000000..af65a8118 --- /dev/null +++ b/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts @@ -0,0 +1,45 @@ +/** OPENAPI-CLASS: get-campaigns-campaign-finance-supplier */ + +import CampaignRoute from "@src/features/routes/CampaignRoute"; +import { tryber } from "@src/features/database"; +import OpenapiError from "@src/features/OpenapiError"; + +type Supplier = { + id: number; + name: string; + created_on?: string; + created_by?: number; +}; + +export default class SupplierRoute extends CampaignRoute<{ + response: StoplightOperations["get-campaigns-campaign-finance-supplier"]["responses"]["200"]["content"]["application/json"]; + parameters: StoplightOperations["get-campaigns-campaign-finance-supplier"]["parameters"]["path"]; +}> { + protected async filter(): Promise { + if (!(await super.filter())) return false; + + if (!this.hasAccessToCampaign(this.cp_id)) { + this.setError(403, new OpenapiError("Access denied")); + + return false; + } + return true; + } + + protected async prepare(): Promise { + const suppliers = await this.getSuppliers(); + + return this.setSuccess(200, { items: suppliers }); + } + + private async getSuppliers(): Promise { + const results = + await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().select( + "id", + "name", + "created_on", + "created_by" + ); + return results; + } +} From 9dc4013eaedc43f0b438aa2fd521fefaa24c0487 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 09:53:37 +0100 Subject: [PATCH 21/31] refactor: enhance tests for finance suppliers endpoint and improve cleanup logic --- .../campaignId/finance/supplier/_get/index.spec.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts b/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts index da5e4c384..c353f0704 100644 --- a/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts +++ b/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts @@ -1,6 +1,7 @@ import request from "supertest"; import app from "@src/app"; import { tryber } from "@src/features/database"; +import { after } from "node:test"; describe("GET /campaigns/campaignId/finance/supplier", () => { beforeAll(async () => { @@ -54,6 +55,13 @@ describe("GET /campaigns/campaignId/finance/supplier", () => { ]); }); + afterAll(async () => { + await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().delete(); + await tryber.tables.WpAppqEvdCampaign.do().delete(); + await tryber.tables.WpUsers.do().delete(); + await tryber.tables.WpAppqEvdProfile.do().delete(); + }); + it("Should return 403 if logged out", async () => { const response = await request(app).get("/campaigns/1/finance/supplier"); expect(response.status).toBe(403); @@ -80,7 +88,7 @@ describe("GET /campaigns/campaignId/finance/supplier", () => { expect(response.status).toBe(200); }); - it("Should return finance suppliers", async () => { + it("Should return finance suppliers - admin", async () => { const response = await request(app) .get("/campaigns/1/finance/supplier") .set("Authorization", "Bearer admin"); @@ -105,7 +113,7 @@ describe("GET /campaigns/campaignId/finance/supplier", () => { expect(response.body.items).toHaveLength(2); }); - it("Should return suppliers with olp permissions", async () => { + it("Should return suppliers - olp permissions", async () => { const response = await request(app) .get("/campaigns/1/finance/supplier") .set("Authorization", 'Bearer tester olp {"appq_campaign":[1]}'); From fab376b89214e739a2738676f4b6317461ea1b71 Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Thu, 29 Jan 2026 13:07:40 +0100 Subject: [PATCH 22/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index dd35be6db..a7f60fe18 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13379,7 +13379,6 @@ paths: type: object required: - name - - id properties: name: type: string @@ -13393,16 +13392,11 @@ paths: type: integer x-stoplight: id: gcs2p8mvl32gc - id: - type: integer - x-stoplight: - id: 3lwwkv3h1vsun examples: Example 2: value: items: - - id: 1 - name: Respondent + - name: Respondent created_at: '2026-01-01' created_by: 10 '400': From d5d4c8149f5d399e12bcefed2c21bd00d8ba1283 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 13:09:58 +0100 Subject: [PATCH 23/31] refactor: remove redundant 'id' field from operations interface --- src/schema.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/schema.ts b/src/schema.ts index a6df456fd..c9c6870f7 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -5605,7 +5605,6 @@ export interface operations { name: string; created_at?: string; created_by?: number; - id: number; }[]; }; }; From 8780256b14c73e8d34aea283c71ed7457499eda4 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 13:10:08 +0100 Subject: [PATCH 24/31] refactor: remove 'id' field from Supplier type and related queries --- .../campaignId/finance/supplier/_get/index.spec.ts | 5 ----- .../campaignId/finance/supplier/_get/index.ts | 14 +++++--------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts b/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts index c353f0704..ee1bf1af0 100644 --- a/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts +++ b/src/routes/campaigns/campaignId/finance/supplier/_get/index.spec.ts @@ -1,7 +1,6 @@ import request from "supertest"; import app from "@src/app"; import { tryber } from "@src/features/database"; -import { after } from "node:test"; describe("GET /campaigns/campaignId/finance/supplier", () => { beforeAll(async () => { @@ -96,13 +95,11 @@ describe("GET /campaigns/campaignId/finance/supplier", () => { expect.objectContaining({ items: expect.arrayContaining([ expect.objectContaining({ - id: 1, name: "Supplier 1", created_by: 1, created_on: "2024-01-01 10:00:00", }), expect.objectContaining({ - id: 2, name: "Supplier 2", created_by: 2, created_on: "2024-01-02 11:00:00", @@ -122,13 +119,11 @@ describe("GET /campaigns/campaignId/finance/supplier", () => { expect.objectContaining({ items: expect.arrayContaining([ expect.objectContaining({ - id: 1, name: "Supplier 1", created_by: 1, created_on: "2024-01-01 10:00:00", }), expect.objectContaining({ - id: 2, name: "Supplier 2", created_by: 2, created_on: "2024-01-02 11:00:00", diff --git a/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts b/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts index af65a8118..807584851 100644 --- a/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts +++ b/src/routes/campaigns/campaignId/finance/supplier/_get/index.ts @@ -5,7 +5,6 @@ import { tryber } from "@src/features/database"; import OpenapiError from "@src/features/OpenapiError"; type Supplier = { - id: number; name: string; created_on?: string; created_by?: number; @@ -33,13 +32,10 @@ export default class SupplierRoute extends CampaignRoute<{ } private async getSuppliers(): Promise { - const results = - await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().select( - "id", - "name", - "created_on", - "created_by" - ); - return results; + return await tryber.tables.WpAppqCampaignOtherCostsSupplier.do().select( + "name", + "created_on", + "created_by" + ); } } From 963432e78037a752b030a480e6911c7ac16572e2 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 17:06:54 +0100 Subject: [PATCH 25/31] refactor: remove duplicated finance suppliers endpoint from campaigns path --- src/schema.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/schema.ts b/src/schema.ts index c9c6870f7..68523450b 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -154,16 +154,6 @@ export interface paths { }; }; }; - "/campaigns/{campaign}/finance/supplier": { - /** Get all suppliers for finance */ - get: operations["get-campaigns-cid-finance-supplier"]; - parameters: { - path: { - /** A campaign id */ - campaign: string; - }; - }; - }; "/campaigns/{campaign}/forms": { get: operations["get-campaigns-campaign-forms"]; parameters: { From 23cf049be0496e44c2b33de9e6bc45da3111309a Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 17:22:53 +0100 Subject: [PATCH 26/31] refactor: update finance supplier endpoint and adjust related operations --- src/reference/openapi.yml | 78 --------------------------------------- src/schema.ts | 66 ++++++++++----------------------- 2 files changed, 20 insertions(+), 124 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index a7f60fe18..0593f1d08 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -3988,84 +3988,6 @@ paths: name: campaign in: path required: true - - schema: - type: string - name: campaign - in: path - required: true - post: - summary: Your POST endpoint - tags: [] - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - attachments: - type: array - items: - type: object - required: - - url - - name - - mime_type - properties: - url: - type: string - - name: - type: string - mime_type: - type: string - failed: - type: array - - items: - type: object - required: - - name - - path - properties: - name: - type: string - path: - type: string - '403': - $ref: '#/components/responses/NotAuthorized' - '500': - description: Internal Server Error - operationId: post-campaigns-campaign-finance-attachments - x-stoplight: - id: 0ucra88nj3skb - security: - - JWT: [] - summary: Get all suppliers - tags: - - Campaign - x-stoplight: - id: hx8pmv3nzamq0 - parameters: - - description: A campaign id - in: path - name: campaign - required: true - schema: - type: string - '/campaigns/{campaign}/finance/attachments': - parameters: - - schema: - type: string - name: campaign - in: path - required: true - - schema: - type: string - name: campaign - in: path - required: true post: summary: Your POST endpoint tags: [] diff --git a/src/schema.ts b/src/schema.ts index 68523450b..f7bd799a7 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -804,17 +804,17 @@ export interface paths { }; }; }; - "/campaigns/{campaign}/finance/type": { - get: operations["get-campaigns-campaign-finance-type"]; + "/campaigns/{campaign}/finance/supplier": { + /** Get all finance suppliers */ + get: operations["get-campaigns-campaign-finance-supplier"]; parameters: { path: { campaign: string; }; }; }; - "/campaigns/{campaign}/finance/supplier": { - /** Get all finance suppliers */ - get: operations["get-campaigns-campaign-finance-supplier"]; + "/campaigns/{campaign}/finance/type": { + get: operations["get-campaigns-campaign-finance-type"]; parameters: { path: { campaign: string; @@ -2177,32 +2177,6 @@ export interface operations { }; }; }; - /** Get all suppliers for finance */ - "get-campaigns-cid-finance-supplier": { - parameters: { - path: { - /** A campaign id */ - campaign: string; - }; - }; - responses: { - /** OK */ - 200: { - content: { - "application/json": { - id: number; - name: string; - created_on?: string; - created_by?: number; - }; - }; - }; - 403: components["responses"]["NotAuthorized"]; - 404: components["responses"]["NotFound"]; - /** Internal Server Error */ - 500: unknown; - }; - }; "get-campaigns-campaign-forms": { parameters: { path: { @@ -5556,7 +5530,8 @@ export interface operations { }; }; }; - "get-campaigns-campaign-finance-type": { + /** Get all finance suppliers */ + "get-campaigns-campaign-finance-supplier": { parameters: { path: { campaign: string; @@ -5568,19 +5543,22 @@ export interface operations { content: { "application/json": { items: { - name?: string; + name: string; + created_at?: string; + created_by?: number; }[]; }; }; }; - 403: components["responses"]["NotAuthorized"]; - 404: components["responses"]["NotFound"]; - /** Shared Response */ + /** Bad Request */ + 400: unknown; + /** Forbidden */ + 403: unknown; + /** Internal Server Error */ 500: unknown; }; }; - /** Get all finance suppliers */ - "get-campaigns-campaign-finance-supplier": { + "get-campaigns-campaign-finance-type": { parameters: { path: { campaign: string; @@ -5592,18 +5570,14 @@ export interface operations { content: { "application/json": { items: { - name: string; - created_at?: string; - created_by?: number; + name?: string; }[]; }; }; }; - /** Bad Request */ - 400: unknown; - /** Forbidden */ - 403: unknown; - /** Internal Server Error */ + 403: components["responses"]["NotAuthorized"]; + 404: components["responses"]["NotFound"]; + /** Shared Response */ 500: unknown; }; }; From 1d1bb3f02cf6a57efada50751db15062ed432cb4 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 17:37:52 +0100 Subject: [PATCH 27/31] refactor: update campaign finance supplier endpoint to remove unnecessary request body and adjust response handling --- src/reference/openapi.yml | 21 --------------------- src/schema.ts | 30 ++++++++++++------------------ 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index 04fb00e09..27ce7c04c 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13389,27 +13389,6 @@ paths: $ref: '#/components/responses/NotFound' '500': description: Internal Server Error - operationId: post-campaigns-campaign-finance-supplier - x-stoplight: - id: j17dlfvjwluu7 - description: Create a new campaign supplier - requestBody: - content: - application/json: - schema: - type: object - required: - - name - properties: - name: - type: string - x-stoplight: - id: bzvnmo26hda42 - examples: - Example 1: - value: - name: Respondent - description: Shared Response operationId: get-campaigns-campaign-finance-type x-stoplight: id: 02e8ns5xdhecm diff --git a/src/schema.ts b/src/schema.ts index 87a035c36..2a3bcf830 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -805,10 +805,19 @@ export interface paths { }; }; "/campaigns/{campaign}/finance/supplier": { - /** Create a new campaign supplier */ - post: operations["post-campaigns-campaign-finance-supplier"]; /** Get all finance suppliers */ get: operations["get-campaigns-campaign-finance-supplier"]; + post: { + parameters: { + path: { + campaign: string; + }; + }; + responses: { + /** Created */ + 201: unknown; + }; + }; parameters: { path: { campaign: string; @@ -5532,8 +5541,6 @@ export interface operations { }; }; }; - /** Create a new campaign supplier */ - "post-campaigns-campaign-finance-supplier": { /** Get all finance suppliers */ "get-campaigns-campaign-finance-supplier": { parameters: { @@ -5542,19 +5549,6 @@ export interface operations { }; }; responses: { - /** Created */ - 201: unknown; - 403: components["responses"]["NotAuthorized"]; - 404: components["responses"]["NotFound"]; - /** Internal Server Error */ - 500: unknown; - }; - requestBody: { - content: { - "application/json": { - name: string; - }; - }; /** OK */ 200: { content: { @@ -5594,7 +5588,7 @@ export interface operations { }; 403: components["responses"]["NotAuthorized"]; 404: components["responses"]["NotFound"]; - /** Shared Response */ + /** Internal Server Error */ 500: unknown; }; }; From 422ea7d99bb175fc532f119d686dcc8fc873f653 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 17:41:44 +0100 Subject: [PATCH 28/31] refactor: enhance post campaign finance supplier endpoint with detailed request and response schemas --- src/reference/openapi.yml | 37 +++++++++++++++++++++++++++++++++- src/schema.ts | 42 +++++++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index 27ce7c04c..f7a4bca71 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -13340,10 +13340,45 @@ paths: required: true post: summary: POST a new supplier - tags: [] + operationId: post-campaigns-campaign-finance-supplier + tags: + - Campaign responses: '201': description: Created + content: + application/json: + schema: + type: object + required: + - id + properties: + id: + type: integer + '400': + description: Bad Request + '403': + description: Forbidden + '500': + description: Internal Server Error + security: + - JWT: [] + requestBody: + content: + application/json: + schema: + type: object + required: + - name + properties: + name: + type: string + examples: + Example 1: + value: + name: Respondent + x-stoplight: + id: j17dlfvjwluu7 '/campaigns/{campaign}/finance/type': parameters: - schema: diff --git a/src/schema.ts b/src/schema.ts index 2a3bcf830..45315b605 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -807,17 +807,7 @@ export interface paths { "/campaigns/{campaign}/finance/supplier": { /** Get all finance suppliers */ get: operations["get-campaigns-campaign-finance-supplier"]; - post: { - parameters: { - path: { - campaign: string; - }; - }; - responses: { - /** Created */ - 201: unknown; - }; - }; + post: operations["post-campaigns-campaign-finance-supplier"]; parameters: { path: { campaign: string; @@ -5569,6 +5559,36 @@ export interface operations { 500: unknown; }; }; + "post-campaigns-campaign-finance-supplier": { + parameters: { + path: { + campaign: string; + }; + }; + responses: { + /** Created */ + 201: { + content: { + "application/json": { + id: number; + }; + }; + }; + /** Bad Request */ + 400: unknown; + /** Forbidden */ + 403: unknown; + /** Internal Server Error */ + 500: unknown; + }; + requestBody: { + content: { + "application/json": { + name: string; + }; + }; + }; + }; "get-campaigns-campaign-finance-type": { parameters: { path: { From 67ec301a5afea4b6004ff5ecdcd9606527c9e2dc Mon Sep 17 00:00:00 2001 From: "it@app-quality.com" Date: Thu, 29 Jan 2026 17:49:30 +0100 Subject: [PATCH 29/31] Modified src/reference/openapi.yml --- src/reference/openapi.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/reference/openapi.yml b/src/reference/openapi.yml index f7a4bca71..26703c487 100644 --- a/src/reference/openapi.yml +++ b/src/reference/openapi.yml @@ -4010,14 +4010,12 @@ paths: properties: url: type: string - name: type: string mime_type: type: string failed: type: array - items: type: object required: @@ -13346,15 +13344,7 @@ paths: responses: '201': description: Created - content: - application/json: - schema: - type: object - required: - - id - properties: - id: - type: integer + content: {} '400': description: Bad Request '403': From a08afd83a6dec283ad94ad02f654f1b442025a29 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 17:50:36 +0100 Subject: [PATCH 30/31] refactor: simplify response schema for post campaign operation --- src/schema.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/schema.ts b/src/schema.ts index 45315b605..e7ab71112 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -5567,13 +5567,7 @@ export interface operations { }; responses: { /** Created */ - 201: { - content: { - "application/json": { - id: number; - }; - }; - }; + 201: unknown; /** Bad Request */ 400: unknown; /** Forbidden */ From cbf0f1e55b39302364f1f8c738d5a356dba58ed0 Mon Sep 17 00:00:00 2001 From: Kariamos Date: Thu, 29 Jan 2026 17:51:00 +0100 Subject: [PATCH 31/31] fix: correct error handling message for supplier creation