From 805da5e07834554024643e1d169b3273f8af63f3 Mon Sep 17 00:00:00 2001 From: yqni13 Date: Mon, 3 Aug 2026 22:24:50 +0200 Subject: [PATCH] refactor: use Number() parsing instead unary "+" --- README.md | 6 +-- backend/package.json | 2 +- .../src/controllers/feedback.controller.ts | 4 +- backend/src/controllers/meta.controller.ts | 6 +-- backend/src/models/feedback-rating.model.ts | 2 +- backend/tests/db-migrations.setup.ts | 2 +- .../middleware/engines.middleware.test.ts | 10 ++--- .../rate-limits.rules.middleware.test.ts | 42 +++++++++---------- docs/CHANGELOG.md | 9 +++- 9 files changed, 43 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 5e2c2c7..542332e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # yqni13 | $\texttt{\color{cornflowerblue}{SUPPORT}}$ -### $\textsf{\color{brown}{v1.6.2}}$ +### $\textsf{\color{brown}{v1.6.3}}$ #### Support hub - handling feedback/ratings (`/feedback`) and bug/support requests (`/tickets`) including file attachments across multiple applications via REST API. Built with NodeJS (Typescript), Express & PostgreSQL in Docker container using API-Key authentication and rate-limiting. Created following Test-Driven Development (450+ tests) and hosting env:prod via Render, Neon and Cloudflare. @@ -215,8 +215,8 @@ Preventing an unwanted merge with unfinished/failed test run, the project is set [see changelog for all updates](/docs/CHANGELOG.md) -$\textsf{[v1.6.1\ =>\ {\textbf{\color{brown}v1.6.2}]}}$ app
-- $\textsf{\color{orange}Patch:}$ Updated 'tickets' routes to prepare for HTTP method .query() to use for path '/search' (not available on current version of Express.js). +$\textsf{[v1.6.2\ =>\ {\textbf{\color{brown}v1.6.3}]}}$ app
+- $\textsf{\color{orange}Patch:}$ Updated number parsing by removing unary "+" operator with Number() fn.
diff --git a/backend/package.json b/backend/package.json index 7ef5bf1..e44d889 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "support_backend", - "version": "1.6.2", + "version": "1.6.3", "appMeta": { "db_version": "1.6.0", "docker_image": "yqni13/support", diff --git a/backend/src/controllers/feedback.controller.ts b/backend/src/controllers/feedback.controller.ts index af97058..6809cba 100644 --- a/backend/src/controllers/feedback.controller.ts +++ b/backend/src/controllers/feedback.controller.ts @@ -8,7 +8,7 @@ class FeedbackController { async getFeedback(req: Request, res: Response, next: NextFunction) { try { checkValidation(req); - const id = (+req.params.id) as FeedbackId; + const id = (Number(req.params.id)) as FeedbackId; const response: FeedbackResponseDTO | null = await feedbackService.getFeedbackById(id); res.json(response); } catch(err: any) { @@ -45,7 +45,7 @@ class FeedbackController { async patchFeedbackReview(req: Request, res: Response, next: NextFunction) { try { checkValidation(req); - const id = (+req.params.id) as FeedbackId; + const id = (Number(req.params.id)) as FeedbackId; const response: FeedbackResponseDTO | null = await feedbackService.updateFeedbackReview(id); res.json(response); } catch(err: any) { diff --git a/backend/src/controllers/meta.controller.ts b/backend/src/controllers/meta.controller.ts index a44a984..e4cebde 100644 --- a/backend/src/controllers/meta.controller.ts +++ b/backend/src/controllers/meta.controller.ts @@ -8,7 +8,7 @@ class MetaController { async getMetaById(req: Request, res: Response, next: NextFunction) { try { checkValidation(req); - const id = (+req.params.id) as MetaId; + const id = (Number(req.params.id)) as MetaId; const response: MetaResponseDTO | null = await metaService.getMetaById(id); res.json(response); } catch(err: any) { @@ -39,7 +39,7 @@ class MetaController { async patchMeta(req: Request, res: Response, next: NextFunction) { try { checkValidation(req); - const id = (+req.params.id) as MetaId; + const id = (Number(req.params.id)) as MetaId; const dto: MetaUpdateDTO = req.body; const response: MetaResponseDTO | null = await metaService.updateMeta(id, dto); res.json(response); @@ -62,7 +62,7 @@ class MetaController { async patchMaintenanceMode(req: Request, res: Response, next: NextFunction) { try { checkValidation(req); - const id = (+req.params.id) as MetaId; + const id = (Number(req.params.id)) as MetaId; const dto: MaintenanceUpdateDTO = req.body; const response: MaintenanceResponseDTO | null = await metaService.updateMaintenanceMode(id, dto); res.json(response); diff --git a/backend/src/models/feedback-rating.model.ts b/backend/src/models/feedback-rating.model.ts index ba74839..afd2527 100644 --- a/backend/src/models/feedback-rating.model.ts +++ b/backend/src/models/feedback-rating.model.ts @@ -34,7 +34,7 @@ class FeedbackRatingModel { toFeedbackRatingResponseDTO(entity: FeedbackRating, extended: false): FeedbackRatingResponseDTO; toFeedbackRatingResponseDTO(entity: FeedbackRating, extended: boolean) { - const delta: number = +((entity.rating_sum / entity.count).toFixed(1)); + const delta: number = Number((entity.rating_sum / entity.count).toFixed(1)); if(extended) { return { client_id: entity.client_id, diff --git a/backend/tests/db-migrations.setup.ts b/backend/tests/db-migrations.setup.ts index 17a71a4..48d17d7 100644 --- a/backend/tests/db-migrations.setup.ts +++ b/backend/tests/db-migrations.setup.ts @@ -16,7 +16,7 @@ export async function runMigrations(testfile: string = 'unknown') { await migrate({ databaseUrl: { host: DB_TEST_HOST, - port: +(DB_TEST_PORT), // convert string to number + port: Number(DB_TEST_PORT), user: DB_TEST_USER, password: DB_TEST_PASS, database: DB_TEST_DATABASE diff --git a/backend/tests/unit-tests/middleware/engines.middleware.test.ts b/backend/tests/unit-tests/middleware/engines.middleware.test.ts index ec9847a..52ae99d 100644 --- a/backend/tests/unit-tests/middleware/engines.middleware.test.ts +++ b/backend/tests/unit-tests/middleware/engines.middleware.test.ts @@ -10,8 +10,6 @@ import { Violation } from "../../../src/utils/enums/violations.enum"; import { default as mockId } from "../../mock-data/id.mock-data.json"; import { ClientsId } from "../../../src/repositories/interfaces/clients.entity.interface"; import { UsersId } from "../../../src/repositories/interfaces/users.entity.interface"; - -// Ensure correct type by converting secret to number via unary + operator. import { secrets } from "../../../src/utils/secrets.utils"; describe('Unit-tests (middleware), priority: class RateLimitsEngine', () => { @@ -42,7 +40,7 @@ describe('Unit-tests (middleware), priority: class RateLimitsEngine', () => { jest.spyOn(rateLimitsService, 'createRateLimit').mockImplementation(); jest.spyOn(ClientsDailyLimitRule.prototype, 'check').mockResolvedValue(null); - const rule: RateLimitsRule = new ClientsDailyLimitRule(+secrets.RATELIMITS_CLIENTSDAILYLIMIT); + const rule: RateLimitsRule = new ClientsDailyLimitRule(Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT)); const count: RateLimitsCount = new RateLimitsIncrement(); const engine = new RateLimitsEngine([rule], count); @@ -65,7 +63,7 @@ describe('Unit-tests (middleware), priority: class RateLimitsEngine', () => { jest.spyOn(ClientsDailyLimitRule.prototype, 'check').mockResolvedValue(response); - const rule: RateLimitsRule = new ClientsDailyLimitRule(+secrets.RATELIMITS_CLIENTSDAILYLIMIT); + const rule: RateLimitsRule = new ClientsDailyLimitRule(Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT)); const count: RateLimitsCount = new RateLimitsIncrement(); const engine = new RateLimitsEngine([rule], count); @@ -85,7 +83,7 @@ describe('Unit-tests (middleware), priority: class RateLimitsEngine', () => { jest.spyOn(demoLimitsService, 'createDemoLimit').mockImplementation(); jest.spyOn(DemoDailyLimitRule.prototype, 'check').mockResolvedValue(null); - const rule: RateLimitsRule = new DemoDailyLimitRule(+secrets.DEMOLIMITS_TOTALDAILYLIMIT); + const rule: RateLimitsRule = new DemoDailyLimitRule(Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT)); const count: RateLimitsCount = new DemoLimitsIncrement(); const engine = new RateLimitsEngine([rule], count); @@ -103,7 +101,7 @@ describe('Unit-tests (middleware), priority: class RateLimitsEngine', () => { jest.spyOn(DemoDailyLimitRule.prototype, 'check').mockResolvedValue(response); - const rule: RateLimitsRule = new DemoDailyLimitRule(+secrets.DEMOLIMITS_TOTALDAILYLIMIT); + const rule: RateLimitsRule = new DemoDailyLimitRule(Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT)); const count: RateLimitsCount = new DemoLimitsIncrement(); const engine = new RateLimitsEngine([rule], count); diff --git a/backend/tests/unit-tests/middleware/rules/rate-limits.rules.middleware.test.ts b/backend/tests/unit-tests/middleware/rules/rate-limits.rules.middleware.test.ts index 3c1b42b..513e626 100644 --- a/backend/tests/unit-tests/middleware/rules/rate-limits.rules.middleware.test.ts +++ b/backend/tests/unit-tests/middleware/rules/rate-limits.rules.middleware.test.ts @@ -20,8 +20,6 @@ import { TicketOption } from "../../../../src/utils/enums/ticket-option.enum"; import { ClientsId } from "../../../../src/repositories/interfaces/clients.entity.interface"; import { UsersId } from "../../../../src/repositories/interfaces/users.entity.interface"; import { TicketsId } from "../../../../src/repositories/interfaces/tickets.entity.interface"; - -// Ensure correct type by converting secret to number via unary + operator. import { secrets } from "../../../../src/utils/secrets.utils" import { MetaId } from "../../../../src/repositories/interfaces/meta.entity.interface"; @@ -168,8 +166,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing valid context calls', () => { test('Params: number of calls within daily limit', async () => { - const ruleCDL = new ClientsDailyLimitRule(+secrets.RATELIMITS_CLIENTSDAILYLIMIT); - const mockCount = +(secrets.RATELIMITS_CLIENTSDAILYLIMIT) - 1; + const ruleCDL = new ClientsDailyLimitRule(Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT)); + const mockCount = Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT) - 1; jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); const expectResult = null; @@ -179,7 +177,7 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () }) test('Params: no existing entry', async () => { - const ruleCDL = new ClientsDailyLimitRule(+secrets.RATELIMITS_CLIENTSDAILYLIMIT); + const ruleCDL = new ClientsDailyLimitRule(Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT)); const mockCount = 0; jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); @@ -193,8 +191,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing invalid context calls', () => { test('Params: number of calls beyond daily limit', async () => { - const ruleCDL = new ClientsDailyLimitRule(+secrets.RATELIMITS_CLIENTSDAILYLIMIT); - const mockCount = +secrets.RATELIMITS_CLIENTSDAILYLIMIT; + const ruleCDL = new ClientsDailyLimitRule(Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT)); + const mockCount = Number(secrets.RATELIMITS_CLIENTSDAILYLIMIT); const testParam_data = structuredClone(mockParam_data); Object.assign(testParam_data, { clients: { flag: null }}); @@ -222,8 +220,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing valid context calls', () => { test('Params: number of calls within daily limit', async () => { - const ruleUDL = new UsersDailyLimitRule(+secrets.RATELIMITS_USERSDAILYLIMIT); - const mockCount = +(secrets.RATELIMITS_USERSDAILYLIMIT) - 1; + const ruleUDL = new UsersDailyLimitRule(Number(secrets.RATELIMITS_USERSDAILYLIMIT)); + const mockCount = Number(secrets.RATELIMITS_USERSDAILYLIMIT) - 1; jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); const expectResult = null; @@ -233,7 +231,7 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () }) test('Params: no existing entry', async () => { - const ruleUDL = new UsersDailyLimitRule(+secrets.RATELIMITS_USERSDAILYLIMIT); + const ruleUDL = new UsersDailyLimitRule(Number(secrets.RATELIMITS_USERSDAILYLIMIT)); const mockCount = 0; jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); @@ -247,8 +245,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing invalid context calls', () => { test('Params: number of calls beyond daily limit', async () => { - const ruleUDL = new UsersDailyLimitRule(+secrets.RATELIMITS_USERSDAILYLIMIT); - const mockCount = +secrets.RATELIMITS_USERSDAILYLIMIT; + const ruleUDL = new UsersDailyLimitRule(Number(secrets.RATELIMITS_USERSDAILYLIMIT)); + const mockCount = Number(secrets.RATELIMITS_USERSDAILYLIMIT); const testParam_data = structuredClone(mockParam_data); Object.assign(testParam_data, { users: { flag: null }}); @@ -276,8 +274,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing valid context calls', () => { test('Params: number of calls within daily limit', async () => { - const ruleTDL = new TotalDailyLimitRule(+secrets.RATELIMITS_TOTALDAILYLIMIT); - const mockCount = +(secrets.RATELIMITS_TOTALDAILYLIMIT) - 1; + const ruleTDL = new TotalDailyLimitRule(Number(secrets.RATELIMITS_TOTALDAILYLIMIT)); + const mockCount = Number(secrets.RATELIMITS_TOTALDAILYLIMIT) - 1; jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); const expectResult = null; @@ -287,7 +285,7 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () }) test('Params: no existing entry', async () => { - const ruleTDL = new TotalDailyLimitRule(+secrets.RATELIMITS_TOTALDAILYLIMIT); + const ruleTDL = new TotalDailyLimitRule(Number(secrets.RATELIMITS_TOTALDAILYLIMIT)); const mockCount = 0; jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); @@ -301,8 +299,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing invalid context calls', () => { test('Params: number of calls beyond daily limit', async () => { - const ruleTDL = new TotalDailyLimitRule(+secrets.RATELIMITS_TOTALDAILYLIMIT); - const mockCount = +secrets.RATELIMITS_TOTALDAILYLIMIT; + const ruleTDL = new TotalDailyLimitRule(Number(secrets.RATELIMITS_TOTALDAILYLIMIT)); + const mockCount = Number(secrets.RATELIMITS_TOTALDAILYLIMIT); jest.spyOn(rateLimitsService, 'getRateLimitCount').mockResolvedValue(mockCount); jest.spyOn(CommonUtils, 'getNextDayUTC').mockReturnValue(mockRetryAfter); @@ -328,8 +326,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing valid context calls', () => { test('Params: number of calls within daily limit', async () => { - const ruleDDL = new DemoDailyLimitRule(+secrets.DEMOLIMITS_TOTALDAILYLIMIT); - const mockCount = +(secrets.DEMOLIMITS_TOTALDAILYLIMIT) - 1; + const ruleDDL = new DemoDailyLimitRule(Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT)); + const mockCount = Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT) - 1; jest.spyOn(demoLimitsService, 'getDemoLimitCount').mockResolvedValue(mockCount); const expectResult = null; @@ -339,7 +337,7 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () }) test('Params: no existing entry', async () => { - const ruleDDL = new DemoDailyLimitRule(+secrets.DEMOLIMITS_TOTALDAILYLIMIT); + const ruleDDL = new DemoDailyLimitRule(Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT)); const mockCount = 0; jest.spyOn(demoLimitsService, 'getDemoLimitCount').mockResolvedValue(mockCount); @@ -353,8 +351,8 @@ describe('Unit-tests (middleware), priority: implementation RateLimitsRule', () describe('Testing invalid context calls', () => { test('Params: number of calls beyond daily limit', async () => { - const ruleDDL = new DemoDailyLimitRule(+secrets.DEMOLIMITS_TOTALDAILYLIMIT); - const mockCount = +secrets.DEMOLIMITS_TOTALDAILYLIMIT; + const ruleDDL = new DemoDailyLimitRule(Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT)); + const mockCount = Number(secrets.DEMOLIMITS_TOTALDAILYLIMIT); jest.spyOn(demoLimitsService, 'getDemoLimitCount').mockResolvedValue(mockCount); jest.spyOn(CommonUtils, 'getNextDayUTC').mockReturnValue(mockRetryAfter); diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 7388578..c67411f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,8 +1,15 @@ ## 📜 $\textsf{\color{salmon}{List\ of\ updates}}$ +### $\textsf{\color{skyblue}2026/08/03}$ + +$\textsf{[v1.6.2\ =>\ {\textbf{\color{brown}v1.6.3}]}}$ app
+- $\textsf{\color{orange}Patch:}$ Updated number parsing by removing unary "+" operator with Number() fn. + +
+ ### $\textsf{\color{skyblue}2026/07/04}$ -$\textsf{[v1.6.1\ =>\ {\textbf{\color{brown}v1.6.2}]}}$ app
+$\textsf{[v1.6.1\ =>\ v1.6.2]}$ app
- $\textsf{\color{orange}Patch:}$ Updated 'tickets' routes to prepare for HTTP method .query() to use for path '/search' (not available on current version of Express.js).