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).