From 38151099589f8fc3dc7e37102c9bf95df65b6280 Mon Sep 17 00:00:00 2001 From: Ravinou Date: Tue, 8 Apr 2025 23:23:20 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20=E2=9A=A1=20config=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers/functions/tokenController.ts | 4 +- pages/api/account/getAppriseAlert.test.ts | 12 +- pages/api/account/getAppriseAlert.ts | 4 +- pages/api/account/getAppriseMode.test.ts | 12 +- pages/api/account/getAppriseMode.ts | 4 +- pages/api/account/getAppriseServices.test.ts | 12 +- pages/api/account/getAppriseServices.ts | 4 +- pages/api/account/getEmailAlert.test.ts | 12 +- pages/api/account/getEmailAlert.ts | 4 +- pages/api/account/sendTestApprise.ts | 4 +- pages/api/account/tokenManager.test.ts | 23 ++-- pages/api/account/tokenManager.ts | 12 +- pages/api/account/updateAppriseAlert.test.ts | 16 +-- pages/api/account/updateAppriseAlert.ts | 6 +- pages/api/account/updateAppriseMode.test.ts | 15 +-- pages/api/account/updateAppriseMode.ts | 6 +- .../api/account/updateAppriseServices.test.ts | 17 +-- pages/api/account/updateAppriseServices.ts | 6 +- pages/api/account/updateEmail.test.ts | 23 ++-- pages/api/account/updateEmail.ts | 6 +- pages/api/account/updateEmailAlert.test.ts | 19 ++- pages/api/account/updateEmailAlert.ts | 6 +- pages/api/account/updatePassword.test.ts | 23 ++-- pages/api/account/updatePassword.ts | 6 +- pages/api/account/updateUsername.test.ts | 23 ++-- pages/api/account/updateUsername.ts | 6 +- pages/api/auth/[...nextauth].ts | 4 +- pages/api/cronjob/checkStatus.test.ts | 59 ++++----- pages/api/cronjob/checkStatus.ts | 8 +- pages/api/cronjob/getStorageUsed.test.ts | 26 ++-- pages/api/cronjob/getStorageUsed.ts | 6 +- pages/api/repo/add.test.ts | 32 ++--- pages/api/repo/add.ts | 6 +- pages/api/repo/id/[slug]/delete.test.ts | 28 ++-- pages/api/repo/id/[slug]/delete.ts | 6 +- pages/api/repo/id/[slug]/edit.test.ts | 30 ++--- pages/api/repo/id/[slug]/edit.ts | 6 +- pages/api/repo/id/[slug]/index.ts | 4 +- pages/api/repo/id/[slug]/repoIndex.test.ts | 10 +- pages/api/repo/index.ts | 4 +- pages/api/repo/repoListIndex.test.ts | 8 +- services/__mocks__/services.ts | 14 ++ services/config.service.ts | 120 +++++++++++------- services/history.service.ts | 36 ------ services/index.ts | 1 - 45 files changed, 322 insertions(+), 371 deletions(-) create mode 100644 services/__mocks__/services.ts delete mode 100644 services/history.service.ts diff --git a/helpers/functions/tokenController.ts b/helpers/functions/tokenController.ts index 80ca1bf..379324b 100644 --- a/helpers/functions/tokenController.ts +++ b/helpers/functions/tokenController.ts @@ -1,7 +1,7 @@ import { IncomingHttpHeaders } from 'http2'; import { Optional } from '~/types'; import { TokenPermissionsType } from '~/types/api/integration.types'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; export const tokenController = async ( headers: IncomingHttpHeaders @@ -17,7 +17,7 @@ export const tokenController = async ( return undefined; } - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const user = usersList.find((u) => u.tokens?.some((t) => t.token === API_KEY)); if (user) { const token = user.tokens?.find((token) => token.token === API_KEY); diff --git a/pages/api/account/getAppriseAlert.test.ts b/pages/api/account/getAppriseAlert.test.ts index 0d81410..62e335a 100644 --- a/pages/api/account/getAppriseAlert.test.ts +++ b/pages/api/account/getAppriseAlert.test.ts @@ -1,12 +1,10 @@ import { getServerSession } from 'next-auth/next'; import { createMocks } from 'node-mocks-http'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import handler from '~/pages/api/account/getAppriseAlert'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('Get Apprise Alert API', () => { beforeEach(() => { @@ -33,7 +31,7 @@ describe('Get Apprise Alert API', () => { user: { name: 'nonexistent' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -58,7 +56,7 @@ describe('Get Apprise Alert API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -80,7 +78,7 @@ describe('Get Apprise Alert API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockImplementation(() => { + vi.mocked(ConfigService.getUsersList).mockImplementation(() => { throw new Error(); }); diff --git a/pages/api/account/getAppriseAlert.ts b/pages/api/account/getAppriseAlert.ts index a3870d7..5621200 100644 --- a/pages/api/account/getAppriseAlert.ts +++ b/pages/api/account/getAppriseAlert.ts @@ -1,6 +1,6 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { ErrorResponse } from '~/types/api/error.types'; import { AppriseAlertResponse } from '~/types/api/notification.types'; import { authOptions } from '../auth/[...nextauth]'; @@ -22,7 +22,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); //Verify that the user of the session exists const user = usersList.find((u) => u.username === session.user?.name); diff --git a/pages/api/account/getAppriseMode.test.ts b/pages/api/account/getAppriseMode.test.ts index d254fc2..81747f9 100644 --- a/pages/api/account/getAppriseMode.test.ts +++ b/pages/api/account/getAppriseMode.test.ts @@ -1,13 +1,11 @@ import { getServerSession } from 'next-auth/next'; import { createMocks } from 'node-mocks-http'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import handler from '~/pages/api/account/getAppriseMode'; import { AppriseModeEnum } from '~/types/domain/config.types'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('Get Apprise Mode API', () => { beforeEach(() => { @@ -34,7 +32,7 @@ describe('Get Apprise Mode API', () => { user: { name: 'nonexistent' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -60,7 +58,7 @@ describe('Get Apprise Mode API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -87,7 +85,7 @@ describe('Get Apprise Mode API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockImplementation(() => { + vi.mocked(ConfigService.getUsersList).mockImplementation(() => { throw new Error(); }); const { req, res } = createMocks({ method: 'GET' }); diff --git a/pages/api/account/getAppriseMode.ts b/pages/api/account/getAppriseMode.ts index f77b71e..5af7ab9 100644 --- a/pages/api/account/getAppriseMode.ts +++ b/pages/api/account/getAppriseMode.ts @@ -1,6 +1,6 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { ErrorResponse } from '~/types/api/error.types'; import { AppriseModeDTO } from '~/types/api/notification.types'; import { authOptions } from '../auth/[...nextauth]'; @@ -20,7 +20,7 @@ export default async function handler( return; } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); //Verify that the user of the session exists const user = usersList.find((u) => u.username === session.user?.name); diff --git a/pages/api/account/getAppriseServices.test.ts b/pages/api/account/getAppriseServices.test.ts index 5defe61..af6b78c 100644 --- a/pages/api/account/getAppriseServices.test.ts +++ b/pages/api/account/getAppriseServices.test.ts @@ -1,12 +1,10 @@ import { getServerSession } from 'next-auth/next'; import { createMocks } from 'node-mocks-http'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import handler from '~/pages/api/account/getAppriseServices'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('Get Apprise Services API', () => { beforeEach(() => { @@ -33,7 +31,7 @@ describe('Get Apprise Services API', () => { user: { name: 'nonexistent' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -58,7 +56,7 @@ describe('Get Apprise Services API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -83,7 +81,7 @@ describe('Get Apprise Services API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockImplementation(() => { + vi.mocked(ConfigService.getUsersList).mockImplementation(() => { throw new Error(); }); diff --git a/pages/api/account/getAppriseServices.ts b/pages/api/account/getAppriseServices.ts index 9f80839..ada5977 100644 --- a/pages/api/account/getAppriseServices.ts +++ b/pages/api/account/getAppriseServices.ts @@ -1,6 +1,6 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { ErrorResponse } from '~/types/api/error.types'; import { AppriseServicesDTO } from '~/types/api/notification.types'; import { authOptions } from '../auth/[...nextauth]'; @@ -20,7 +20,7 @@ export default async function handler( return; } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); //Verify that the user of the session exists const user = usersList.find((u) => u.username === session.user?.name); diff --git a/pages/api/account/getEmailAlert.test.ts b/pages/api/account/getEmailAlert.test.ts index 372c0de..5af5727 100644 --- a/pages/api/account/getEmailAlert.test.ts +++ b/pages/api/account/getEmailAlert.test.ts @@ -1,12 +1,10 @@ import { getServerSession } from 'next-auth/next'; import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/getEmailAlert'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('Get Email Alert API', () => { beforeEach(() => { @@ -33,7 +31,7 @@ describe('Get Email Alert API', () => { user: { name: 'nonexistent' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -58,7 +56,7 @@ describe('Get Email Alert API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -83,7 +81,7 @@ describe('Get Email Alert API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockImplementation(() => { + vi.mocked(ConfigService.getUsersList).mockImplementation(() => { throw new Error(); }); diff --git a/pages/api/account/getEmailAlert.ts b/pages/api/account/getEmailAlert.ts index 55abb8b..5703075 100644 --- a/pages/api/account/getEmailAlert.ts +++ b/pages/api/account/getEmailAlert.ts @@ -1,7 +1,7 @@ //Lib import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { ErrorResponse } from '~/types/api/error.types'; import { EmailAlertDTO } from '~/types/api/notification.types'; import { authOptions } from '../auth/[...nextauth]'; @@ -23,7 +23,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); //Verify that the user of the session exists const user = usersList.find((u) => u.username === session.user?.name); diff --git a/pages/api/account/sendTestApprise.ts b/pages/api/account/sendTestApprise.ts index 8bf0406..c7ca601 100644 --- a/pages/api/account/sendTestApprise.ts +++ b/pages/api/account/sendTestApprise.ts @@ -2,7 +2,7 @@ import { exec } from 'child_process'; import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; import { promisify } from 'util'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { ErrorResponse, SuccessResponse } from '~/types/api/error.types'; import { authOptions } from '../auth/[...nextauth]'; @@ -43,7 +43,7 @@ export default async function handler( if (!session) return res.status(401).json({ message: 'You must be logged in.' }); try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const user = usersList.find((u) => u.username === session.user?.name); if (!user) return res.status(400).json({ message: 'Invalid user session. Please log out and retry.' }); diff --git a/pages/api/account/tokenManager.test.ts b/pages/api/account/tokenManager.test.ts index 9fa35e5..9728716 100644 --- a/pages/api/account/tokenManager.test.ts +++ b/pages/api/account/tokenManager.test.ts @@ -1,7 +1,7 @@ import handler from '~/pages/api/account/tokenManager'; import { createMocks } from 'node-mocks-http'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import ApiResponse from '~/helpers/functions/apiResponse'; vi.mock('next-auth/next', () => ({ @@ -9,10 +9,7 @@ vi.mock('next-auth/next', () => ({ getServerSession: vi.fn(), })); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); vi.mock('~/helpers/functions/apiResponse'); @@ -40,7 +37,7 @@ describe('Token Manager API', () => { it('should create a new token if valid data is provided', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testUser' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testUser', @@ -50,7 +47,7 @@ describe('Token Manager API', () => { tokens: [], }, ]); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'POST', @@ -65,12 +62,12 @@ describe('Token Manager API', () => { expect(res._getStatusCode()).toBe(200); const responseData = JSON.parse(res._getData()); expect(responseData).toHaveProperty('token'); - expect(updateUsersList).toHaveBeenCalled(); + expect(ConfigService.updateUsersList).toHaveBeenCalled(); }); it('should return bad request if token name already exists', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testUser' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testUser', @@ -103,7 +100,7 @@ describe('Token Manager API', () => { it('should return token list for GET request', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testUser' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testUser', @@ -149,7 +146,7 @@ describe('Token Manager API', () => { it('should delete a token for DELETE request', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testUser' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testUser', @@ -172,7 +169,7 @@ describe('Token Manager API', () => { ], }, ]); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'DELETE', @@ -182,7 +179,7 @@ describe('Token Manager API', () => { await handler(req, res); expect(ApiResponse.success).toHaveBeenCalledWith(res, 'Token deleted'); - expect(updateUsersList).toHaveBeenCalled(); + expect(ConfigService.updateUsersList).toHaveBeenCalled(); }); it('should return bad request if token name is missing in DELETE request', async () => { diff --git a/pages/api/account/tokenManager.ts b/pages/api/account/tokenManager.ts index 3fc08bd..899db13 100644 --- a/pages/api/account/tokenManager.ts +++ b/pages/api/account/tokenManager.ts @@ -3,7 +3,7 @@ import { getServerSession } from 'next-auth/next'; import { NextApiRequest, NextApiResponse } from 'next'; import { IntegrationTokenType, TokenPermissionsType } from '~/types/api/integration.types'; import ApiResponse from '~/helpers/functions/apiResponse'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { getUnixTime } from 'date-fns'; import { v4 as uuidv4 } from 'uuid'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; @@ -33,7 +33,7 @@ export default async function handler( try { const { name, permissions } = req.body as IntegrationTokenType; - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const user = usersList.find((u) => u.username === session.user.name); if (!user) { return ApiResponse.unauthorized(res); @@ -58,7 +58,7 @@ export default async function handler( return u; }); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ token: newToken.token }); } catch (error) { console.log(error); @@ -66,7 +66,7 @@ export default async function handler( } } else if (req.method == 'GET') { try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const user = usersList.find((u) => u.username === session.user.name); if (!user) { return ApiResponse.unauthorized(res); @@ -86,7 +86,7 @@ export default async function handler( } } else if (req.method == 'DELETE') { try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const user = usersList.find((u) => u.username === session.user.name); if (!user) { return ApiResponse.unauthorized(res); @@ -109,7 +109,7 @@ export default async function handler( return u; }); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return ApiResponse.success(res, 'Token deleted'); } catch (error) { console.log(error); diff --git a/pages/api/account/updateAppriseAlert.test.ts b/pages/api/account/updateAppriseAlert.test.ts index 5dc315b..2700ffb 100644 --- a/pages/api/account/updateAppriseAlert.test.ts +++ b/pages/api/account/updateAppriseAlert.test.ts @@ -1,14 +1,10 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updateAppriseAlert'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - __esModule: true, - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('Notifications API', () => { beforeEach(() => { @@ -48,7 +44,7 @@ describe('Notifications API', () => { user: { name: 'nonexistent' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -72,7 +68,7 @@ describe('Notifications API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -86,7 +82,7 @@ describe('Notifications API', () => { const { req, res } = createMocks({ method: 'PUT', body: { appriseAlert: true } }); await handler(req, res); - expect(updateUsersList).toHaveBeenCalledWith([ + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ { id: 1, username: 'testuser', @@ -105,7 +101,7 @@ describe('Notifications API', () => { user: { name: 'testuser' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'ENOENT' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'ENOENT' }); const { req, res } = createMocks({ method: 'PUT', body: { appriseAlert: true } }); await handler(req, res); diff --git a/pages/api/account/updateAppriseAlert.ts b/pages/api/account/updateAppriseAlert.ts index 73325fd..cc3f4ce 100644 --- a/pages/api/account/updateAppriseAlert.ts +++ b/pages/api/account/updateAppriseAlert.ts @@ -1,5 +1,5 @@ // Imports -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { authOptions } from '../auth/[...nextauth]'; import { getServerSession } from 'next-auth/next'; import { NextApiRequest, NextApiResponse } from 'next'; @@ -25,7 +25,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((u) => u.username === session.user?.name); if (userIndex === -1) { @@ -38,7 +38,7 @@ export default async function handler( index === userIndex ? { ...user, appriseAlert } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { console.log(error); diff --git a/pages/api/account/updateAppriseMode.test.ts b/pages/api/account/updateAppriseMode.test.ts index 6011d56..8c585aa 100644 --- a/pages/api/account/updateAppriseMode.test.ts +++ b/pages/api/account/updateAppriseMode.test.ts @@ -1,14 +1,11 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updateAppriseMode'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { AppriseModeEnum } from '~/types/domain/config.types'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('Apprise Mode API', () => { it('should return 405 if method is not PUT', async () => { @@ -40,7 +37,7 @@ describe('Apprise Mode API', () => { it('should return 400 if user does not exist', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'unknownuser' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -62,7 +59,7 @@ describe('Apprise Mode API', () => { it('should update user settings and return 200', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testuser' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'testuser', @@ -72,7 +69,7 @@ describe('Apprise Mode API', () => { appriseMode: AppriseModeEnum.PACKAGE, }, ]); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PUT', @@ -81,7 +78,7 @@ describe('Apprise Mode API', () => { await handler(req, res); - expect(updateUsersList).toHaveBeenCalledWith([ + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ { id: 1, username: 'testuser', diff --git a/pages/api/account/updateAppriseMode.ts b/pages/api/account/updateAppriseMode.ts index 9d01cfe..36eb836 100644 --- a/pages/api/account/updateAppriseMode.ts +++ b/pages/api/account/updateAppriseMode.ts @@ -1,4 +1,4 @@ -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { authOptions } from '../auth/[...nextauth]'; import { getServerSession } from 'next-auth/next'; import { NextApiRequest, NextApiResponse } from 'next'; @@ -25,7 +25,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((user) => user.username === session.user?.name); if (userIndex === -1) { @@ -38,7 +38,7 @@ export default async function handler( index === userIndex ? { ...user, appriseMode, appriseStatelessURL } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { console.log(error); diff --git a/pages/api/account/updateAppriseServices.test.ts b/pages/api/account/updateAppriseServices.test.ts index 510f5a7..d0d7a10 100644 --- a/pages/api/account/updateAppriseServices.test.ts +++ b/pages/api/account/updateAppriseServices.test.ts @@ -1,13 +1,10 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updateAppriseServices'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('PUT /api/account/updateAppriseURLs', () => { beforeEach(() => { @@ -40,7 +37,7 @@ describe('PUT /api/account/updateAppriseURLs', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'Ada', @@ -67,7 +64,7 @@ describe('PUT /api/account/updateAppriseURLs', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'Lovelace', @@ -77,7 +74,7 @@ describe('PUT /api/account/updateAppriseURLs', () => { appriseServices: [], }, ]); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PUT', @@ -94,7 +91,7 @@ describe('PUT /api/account/updateAppriseURLs', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'ENOENT' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'ENOENT' }); const { req, res } = createMocks({ method: 'PUT', @@ -114,7 +111,7 @@ describe('PUT /api/account/updateAppriseURLs', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'UNKNOWN_ERROR' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'UNKNOWN_ERROR' }); const { req, res } = createMocks({ method: 'PUT', diff --git a/pages/api/account/updateAppriseServices.ts b/pages/api/account/updateAppriseServices.ts index 4ffcf8e..7cc8165 100644 --- a/pages/api/account/updateAppriseServices.ts +++ b/pages/api/account/updateAppriseServices.ts @@ -4,7 +4,7 @@ import { getServerSession } from 'next-auth/next'; import { NextApiRequest, NextApiResponse } from 'next'; import { AppriseServicesDTO } from '~/types/api/notification.types'; import { ErrorResponse } from '~/types/api/error.types'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; export default async function handler( req: NextApiRequest & { body: AppriseServicesDTO }, @@ -22,7 +22,7 @@ export default async function handler( const { appriseURLs } = req.body; try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((user) => user.username === session.user?.name); if (userIndex === -1) { @@ -41,7 +41,7 @@ export default async function handler( index === userIndex ? { ...user, appriseServices: appriseURLsArray } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { console.log(error); diff --git a/pages/api/account/updateEmail.test.ts b/pages/api/account/updateEmail.test.ts index fbc881d..4f11df7 100644 --- a/pages/api/account/updateEmail.test.ts +++ b/pages/api/account/updateEmail.test.ts @@ -1,13 +1,10 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updateEmail'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('PUT /api/account/updateEmail', () => { beforeEach(() => { @@ -52,7 +49,7 @@ describe('PUT /api/account/updateEmail', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'Ada', email: 'ada@example.com', password: '', roles: [] }, ]); @@ -74,7 +71,7 @@ describe('PUT /api/account/updateEmail', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'Lovelace', email: 'lovelace@example.com', password: '', roles: [] }, { id: 2, username: 'Ada', email: 'new@example.com', password: '', roles: [] }, ]); @@ -99,8 +96,8 @@ describe('PUT /api/account/updateEmail', () => { { id: 1, username: 'Lovelace', email: 'lovelace@example.com', password: '', roles: [] }, ]; - vi.mocked(getUsersList).mockResolvedValue(users); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.getUsersList).mockResolvedValue(users); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PUT', @@ -109,7 +106,9 @@ describe('PUT /api/account/updateEmail', () => { await handler(req, res); - expect(updateUsersList).toHaveBeenCalledWith([{ ...users[0], email: 'new@example.com' }]); + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ + { ...users[0], email: 'new@example.com' }, + ]); expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ message: 'Successful API send' }); }); @@ -119,7 +118,7 @@ describe('PUT /api/account/updateEmail', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'ENOENT' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'ENOENT' }); const { req, res } = createMocks({ method: 'PUT', @@ -140,7 +139,7 @@ describe('PUT /api/account/updateEmail', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'UNKNOWN_ERROR' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'UNKNOWN_ERROR' }); const { req, res } = createMocks({ method: 'PUT', diff --git a/pages/api/account/updateEmail.ts b/pages/api/account/updateEmail.ts index 79ea34d..9bf5e53 100644 --- a/pages/api/account/updateEmail.ts +++ b/pages/api/account/updateEmail.ts @@ -1,4 +1,4 @@ -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { authOptions } from '../auth/[...nextauth]'; import { getServerSession } from 'next-auth/next'; import { NextApiRequest, NextApiResponse } from 'next'; @@ -25,7 +25,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((user) => user.username === session.user?.name); if (userIndex === -1) { @@ -42,7 +42,7 @@ export default async function handler( index === userIndex ? { ...user, email } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { console.log(error); diff --git a/pages/api/account/updateEmailAlert.test.ts b/pages/api/account/updateEmailAlert.test.ts index 3493f7b..243e696 100644 --- a/pages/api/account/updateEmailAlert.test.ts +++ b/pages/api/account/updateEmailAlert.test.ts @@ -1,13 +1,10 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updateEmailAlert'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('PUT /api/account/updateEmailAlert', () => { beforeEach(() => { @@ -52,7 +49,7 @@ describe('PUT /api/account/updateEmailAlert', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 2, username: 'Ada', @@ -90,8 +87,8 @@ describe('PUT /api/account/updateEmailAlert', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([user]); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.getUsersList).mockResolvedValue([user]); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PUT', @@ -100,7 +97,7 @@ describe('PUT /api/account/updateEmailAlert', () => { await handler(req, res); - expect(updateUsersList).toHaveBeenCalledWith([{ ...user, emailAlert: true }]); + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([{ ...user, emailAlert: true }]); expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ message: 'Successful API send' }); }); @@ -110,7 +107,7 @@ describe('PUT /api/account/updateEmailAlert', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'ENOENT' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'ENOENT' }); const { req, res } = createMocks({ method: 'PUT', @@ -131,7 +128,7 @@ describe('PUT /api/account/updateEmailAlert', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'UNKNOWN' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'UNKNOWN' }); const { req, res } = createMocks({ method: 'PUT', diff --git a/pages/api/account/updateEmailAlert.ts b/pages/api/account/updateEmailAlert.ts index 492d844..fcc52b2 100644 --- a/pages/api/account/updateEmailAlert.ts +++ b/pages/api/account/updateEmailAlert.ts @@ -1,4 +1,4 @@ -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { authOptions } from '../auth/[...nextauth]'; import { getServerSession } from 'next-auth/next'; import { EmailAlertDTO } from '~/types/api/notification.types'; @@ -25,7 +25,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((u) => u.username === session.user?.name); if (userIndex === -1) { @@ -38,7 +38,7 @@ export default async function handler( index === userIndex ? { ...user, emailAlert } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { console.log(error); diff --git a/pages/api/account/updatePassword.test.ts b/pages/api/account/updatePassword.test.ts index 56c5435..881390e 100644 --- a/pages/api/account/updatePassword.test.ts +++ b/pages/api/account/updatePassword.test.ts @@ -1,14 +1,11 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updatePassword'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { verifyPassword, hashPassword } from '~/helpers/functions'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); vi.mock('~/helpers/functions', () => ({ verifyPassword: vi.fn(), hashPassword: vi.fn(), @@ -57,7 +54,7 @@ describe('PUT /api/account/updatePassword', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'Ada', password: 'hashedpass', roles: [], email: 'ada@example.com' }, ]); @@ -79,7 +76,7 @@ describe('PUT /api/account/updatePassword', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, username: 'Lovelace', password: 'hashedpass', roles: [], email: 'love@example.com' }, ]); @@ -109,11 +106,11 @@ describe('PUT /api/account/updatePassword', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockResolvedValue([oldUser]); + vi.mocked(ConfigService.getUsersList).mockResolvedValue([oldUser]); vi.mocked(verifyPassword).mockResolvedValue(true); vi.mocked(hashPassword).mockResolvedValue('newHashedPassword'); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PUT', @@ -124,7 +121,9 @@ describe('PUT /api/account/updatePassword', () => { expect(verifyPassword).toHaveBeenCalledWith('oldpass', 'hashedpass'); expect(hashPassword).toHaveBeenCalledWith('newpass'); - expect(updateUsersList).toHaveBeenCalledWith([{ ...oldUser, password: 'newHashedPassword' }]); + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ + { ...oldUser, password: 'newHashedPassword' }, + ]); expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ message: 'Successful API send' }); }); @@ -134,7 +133,7 @@ describe('PUT /api/account/updatePassword', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'ENOENT' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'ENOENT' }); const { req, res } = createMocks({ method: 'PUT', @@ -155,7 +154,7 @@ describe('PUT /api/account/updatePassword', () => { user: { name: 'Lovelace' }, }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'SOMETHING_ELSE' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'SOMETHING_ELSE' }); const { req, res } = createMocks({ method: 'PUT', diff --git a/pages/api/account/updatePassword.ts b/pages/api/account/updatePassword.ts index 655d94f..caf148e 100644 --- a/pages/api/account/updatePassword.ts +++ b/pages/api/account/updatePassword.ts @@ -1,6 +1,6 @@ import { hashPassword, verifyPassword } from '~/helpers/functions'; import { authOptions } from '../auth/[...nextauth]'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { getServerSession } from 'next-auth/next'; import { NextApiRequest, NextApiResponse } from 'next'; import { ErrorResponse } from '~/types/api/error.types'; @@ -26,7 +26,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((user) => user.username === session.user?.name); const user = usersList[userIndex]; @@ -46,7 +46,7 @@ export default async function handler( index === userIndex ? { ...user, password: newPasswordHash } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { diff --git a/pages/api/account/updateUsername.test.ts b/pages/api/account/updateUsername.test.ts index f8b41f2..d4b4b8f 100644 --- a/pages/api/account/updateUsername.test.ts +++ b/pages/api/account/updateUsername.test.ts @@ -1,13 +1,10 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/account/updateUsername'; import { getServerSession } from 'next-auth/next'; -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; vi.mock('next-auth/next'); -vi.mock('~/services', () => ({ - getUsersList: vi.fn(), - updateUsersList: vi.fn(), -})); +vi.mock('~/services'); describe('PUT /api/account/updateUsername', () => { beforeEach(() => { @@ -66,7 +63,7 @@ describe('PUT /api/account/updateUsername', () => { it('should return 400 if user is not found', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'Lovelace' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { username: 'Ada', email: 'ada@example.com', password: 'xxx', id: 1, roles: ['user'] }, ]); @@ -86,7 +83,7 @@ describe('PUT /api/account/updateUsername', () => { it('should return 400 if new username already exists', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'Lovelace' } }); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { username: 'Lovelace', email: 'love@example.com', password: 'xxx', id: 1, roles: ['user'] }, { username: 'newname', @@ -119,8 +116,8 @@ describe('PUT /api/account/updateUsername', () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'Lovelace' } }); - vi.mocked(getUsersList).mockResolvedValue([originalUser]); - vi.mocked(updateUsersList).mockResolvedValue(); + vi.mocked(ConfigService.getUsersList).mockResolvedValue([originalUser]); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PUT', @@ -129,14 +126,16 @@ describe('PUT /api/account/updateUsername', () => { await handler(req, res); - expect(updateUsersList).toHaveBeenCalledWith([{ ...originalUser, username: 'newusername' }]); + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ + { ...originalUser, username: 'newusername' }, + ]); expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ message: 'Successful API send' }); }); it('should return 500 if file not found (ENOENT)', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'Lovelace' } }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'ENOENT' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'ENOENT' }); const { req, res } = createMocks({ method: 'PUT', @@ -154,7 +153,7 @@ describe('PUT /api/account/updateUsername', () => { it('should return 500 on unknown error', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'Lovelace' } }); - vi.mocked(getUsersList).mockRejectedValue({ code: 'SOMETHING_ELSE' }); + vi.mocked(ConfigService.getUsersList).mockRejectedValue({ code: 'SOMETHING_ELSE' }); const { req, res } = createMocks({ method: 'PUT', diff --git a/pages/api/account/updateUsername.ts b/pages/api/account/updateUsername.ts index 9c2bd21..961561a 100644 --- a/pages/api/account/updateUsername.ts +++ b/pages/api/account/updateUsername.ts @@ -1,4 +1,4 @@ -import { getUsersList, updateUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { authOptions } from '../auth/[...nextauth]'; import { getServerSession } from 'next-auth/next'; import { UsernameSettingDTO } from '~/types/api/setting.types'; @@ -33,7 +33,7 @@ export default async function handler( } try { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); const userIndex = usersList.findIndex((user) => user.username === session.user?.name); if (userIndex === -1) { @@ -49,7 +49,7 @@ export default async function handler( const updatedUsersList = usersList.map((user, index) => index === userIndex ? { ...user, username } : user ); - await updateUsersList(updatedUsersList); + await ConfigService.updateUsersList(updatedUsersList); return res.status(200).json({ message: 'Successful API send' }); } catch (error: any) { diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 7dc18b1..77521ea 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -2,7 +2,7 @@ import fs from 'fs'; import NextAuth, { NextAuthOptions, RequestInternal, User } from 'next-auth'; import CredentialsProvider from 'next-auth/providers/credentials'; import path from 'path'; -import { getUsersList } from '~/services'; +import { ConfigService } from '~/services'; import { verifyPassword } from '../../../helpers/functions/auth'; const logLogin = async (message: string, req: Partial, success = false) => { @@ -53,7 +53,7 @@ export const authOptions: NextAuthOptions = { ); } - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); //Step 1 : does the user exist ? const userIndex = usersList.map((user) => user.username).indexOf(username.toLowerCase()); diff --git a/pages/api/cronjob/checkStatus.test.ts b/pages/api/cronjob/checkStatus.test.ts index 6d621ef..393013c 100644 --- a/pages/api/cronjob/checkStatus.test.ts +++ b/pages/api/cronjob/checkStatus.test.ts @@ -1,17 +1,10 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/cronjob/checkStatus'; -import { getRepoList, getUsersList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; import nodemailerSMTP from '~/helpers/functions/nodemailerSMTP'; import { AppriseModeEnum } from '~/types/domain/config.types'; -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), - getUsersList: vi.fn(), - updateRepoList: vi.fn(), - ShellService: { - getLastSaveList: vi.fn(), - }, -})); +vi.mock('~/services'); vi.mock('~/helpers/functions/nodemailerSMTP', () => ({ default: vi.fn(() => ({ @@ -70,7 +63,7 @@ describe('Cronjob API Handler', () => { }); it('should return 200 with message if no repository to check (empty repoList)', async () => { - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); vi.mocked(ShellService.getLastSaveList).mockResolvedValue([ { repositoryName: 'repo1', lastSave: 123 }, ]); @@ -89,7 +82,7 @@ describe('Cronjob API Handler', () => { }); it('should return 200 with message if no repository to check (empty lastSaveList)', async () => { - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alert: 100, @@ -120,7 +113,7 @@ describe('Cronjob API Handler', () => { it('should execute successfully without alerts if all repositories are OK', async () => { const currentTime = Math.floor(Date.now() / 1000); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alert: 1000, @@ -137,8 +130,8 @@ describe('Cronjob API Handler', () => { vi.mocked(ShellService.getLastSaveList).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime }, ]); - vi.mocked(updateRepoList).mockResolvedValue(undefined); - vi.mocked(getUsersList).mockResolvedValue([]); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(undefined); + vi.mocked(ConfigService.getUsersList).mockResolvedValue([]); const { req, res } = createMocks({ method: 'POST', @@ -151,11 +144,11 @@ describe('Cronjob API Handler', () => { status: 200, message: 'Status cron executed successfully.', }); - expect(updateRepoList).toHaveBeenCalled(); + expect(ConfigService.updateRepoList).toHaveBeenCalled(); }); it('should return 500 if an error occurs', async () => { - vi.mocked(getRepoList).mockRejectedValue(new Error('Test error')); + vi.mocked(ConfigService.getRepoList).mockRejectedValue(new Error('Test error')); const { req, res } = createMocks({ method: 'POST', @@ -173,7 +166,7 @@ describe('Cronjob API Handler', () => { it('should not send email alert if emailAlert is false', async () => { const currentTime = Math.floor(Date.now() / 1000); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alert: 100, @@ -191,7 +184,7 @@ describe('Cronjob API Handler', () => { { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); // User has disabled email alert but enabled Apprise alert - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, password: 'hashed-password', @@ -217,7 +210,7 @@ describe('Cronjob API Handler', () => { it('should not send apprise alert if appriseAlert is false', async () => { const currentTime = Math.floor(Date.now() / 1000); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alert: 100, @@ -235,7 +228,7 @@ describe('Cronjob API Handler', () => { { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); // User has disabled Apprise alert but enabled email alert - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, password: 'hashed-password', @@ -264,7 +257,7 @@ describe('Cronjob API Handler', () => { it('should not send alert if alert is disabled on repo (repo.alert === 0)', async () => { const currentTime = Math.floor(Date.now() / 1000); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alert: 0, @@ -281,7 +274,7 @@ describe('Cronjob API Handler', () => { vi.mocked(ShellService.getLastSaveList).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 1000 }, ]); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, password: 'hashed-password', @@ -309,7 +302,7 @@ describe('Cronjob API Handler', () => { }); it('should not update lastStatusAlertSend or add to repoListToSendAlert if repo status is OK', async () => { - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', status: true, @@ -324,7 +317,7 @@ describe('Cronjob API Handler', () => { lastStatusAlertSend: 1000, }, ]); - vi.mocked(updateRepoList).mockResolvedValue(undefined); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(undefined); vi.mocked(ShellService.getLastSaveList).mockResolvedValue([ { repositoryName: 'repo1', lastSave: Math.floor(Date.now() / 1000) }, ]); @@ -336,7 +329,7 @@ describe('Cronjob API Handler', () => { await handler(req, res); - expect(updateRepoList).toHaveBeenCalledWith([ + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([ { repositoryName: 'repo1', status: true, @@ -356,7 +349,7 @@ describe('Cronjob API Handler', () => { it('should update lastStatusAlertSend if repo is down and alert is enabled', async () => { const currentTime = 1741535661; - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alias: 'Repo1', @@ -373,7 +366,7 @@ describe('Cronjob API Handler', () => { vi.mocked(ShellService.getLastSaveList).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, password: 'hashed-password', @@ -391,7 +384,7 @@ describe('Cronjob API Handler', () => { await handler(req, res); - expect(updateRepoList).toHaveBeenCalledWith([ + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([ { repositoryName: 'repo1', alias: 'Repo1', @@ -411,7 +404,7 @@ describe('Cronjob API Handler', () => { it('should not update lastStatusAlertSend or send alerts if alert is disabled', async () => { const currentTime = Math.floor(Date.now() / 1000); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alias: 'Repo1', @@ -437,7 +430,7 @@ describe('Cronjob API Handler', () => { await handler(req, res); - expect(updateRepoList).toHaveBeenCalledWith([ + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([ { repositoryName: 'repo1', alias: 'Repo1', @@ -458,7 +451,7 @@ describe('Cronjob API Handler', () => { it('should update lastStatusAlertSend only if the last alert was sent more than 90000 seconds ago', async () => { const currentTime = Math.floor(Date.now() / 1000); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { repositoryName: 'repo1', alias: 'Repo1', @@ -476,7 +469,7 @@ describe('Cronjob API Handler', () => { vi.mocked(ShellService.getLastSaveList).mockResolvedValue([ { repositoryName: 'repo1', lastSave: currentTime - 200 }, ]); - vi.mocked(getUsersList).mockResolvedValue([ + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ { id: 1, password: 'hashed-password', @@ -494,7 +487,7 @@ describe('Cronjob API Handler', () => { await handler(req, res); - expect(updateRepoList).toHaveBeenCalledWith([ + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([ { repositoryName: 'repo1', alias: 'Repo1', diff --git a/pages/api/cronjob/checkStatus.ts b/pages/api/cronjob/checkStatus.ts index eafa2d8..34ccbda 100644 --- a/pages/api/cronjob/checkStatus.ts +++ b/pages/api/cronjob/checkStatus.ts @@ -3,7 +3,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { exec as execCallback } from 'node:child_process'; import { promisify } from 'util'; import ApiResponse from '~/helpers/functions/apiResponse'; -import { getRepoList, getUsersList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; import nodemailerSMTP from '~/helpers/functions/nodemailerSMTP'; import emailAlertStatus from '~/helpers/templates/emailAlertStatus'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; @@ -26,7 +26,7 @@ export default async function handler( } try { - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); const lastSaveList = await ShellService.getLastSaveList(); if (repoList.length === 0 || lastSaveList.length === 0) { return ApiResponse.success(res, 'Status cron executed. No repository to check.'); @@ -58,7 +58,7 @@ export default async function handler( }); if (repoListToSendAlert.length > 0) { - const usersList = await getUsersList(); + const usersList = await ConfigService.getUsersList(); // Send Email Alert if (usersList[0].emailAlert) { @@ -91,7 +91,7 @@ export default async function handler( } } - await updateRepoList(updatedRepoList); + await ConfigService.updateRepoList(updatedRepoList); return ApiResponse.success(res, 'Status cron executed successfully.'); } catch (error) { console.log(error); diff --git a/pages/api/cronjob/getStorageUsed.test.ts b/pages/api/cronjob/getStorageUsed.test.ts index 8d50c00..e226d34 100644 --- a/pages/api/cronjob/getStorageUsed.test.ts +++ b/pages/api/cronjob/getStorageUsed.test.ts @@ -1,14 +1,8 @@ import handler from '~/pages/api/cronjob/getStorageUsed'; import { createMocks } from 'node-mocks-http'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), - updateRepoList: vi.fn(), - ShellService: { - getStorageUsed: vi.fn(), - }, -})); +vi.mock('~/services'); describe('GET /api/cronjob/getStorageUsed', () => { beforeEach(() => { @@ -43,7 +37,7 @@ describe('GET /api/cronjob/getStorageUsed', () => { }); it('should return success if no repositories are found', async () => { - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); const { req, res } = createMocks({ method: 'POST', @@ -68,9 +62,9 @@ describe('GET /api/cronjob/getStorageUsed', () => { { name: 'repo2', size: 200 }, ]; - vi.mocked(getRepoList).mockResolvedValue(mockRepoList); + vi.mocked(ConfigService.getRepoList).mockResolvedValue(mockRepoList); vi.mocked(ShellService.getStorageUsed).mockResolvedValue(mockStorageUsed); - vi.mocked(updateRepoList).mockResolvedValue(undefined); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(undefined); const { req, res } = createMocks({ method: 'POST', @@ -83,14 +77,14 @@ describe('GET /api/cronjob/getStorageUsed', () => { expect(res._getStatusCode()).toBe(200); expect(res._getData()).toContain('Storage cron has been executed'); - expect(updateRepoList).toHaveBeenCalledWith([ + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([ { repositoryName: 'repo1', storageUsed: 100 }, { repositoryName: 'repo2', storageUsed: 200 }, ]); }); it('should return server error if an exception occurs', async () => { - vi.mocked(getRepoList).mockRejectedValue(new Error('Test error')); + vi.mocked(ConfigService.getRepoList).mockRejectedValue(new Error('Test error')); const { req, res } = createMocks({ method: 'POST', @@ -111,9 +105,9 @@ describe('GET /api/cronjob/getStorageUsed', () => { ]; const mockStorageUsed = [{ name: 'repo1', size: 100 }]; - vi.mocked(getRepoList).mockResolvedValue(mockRepoList); + vi.mocked(ConfigService.getRepoList).mockResolvedValue(mockRepoList); vi.mocked(ShellService.getStorageUsed).mockResolvedValue(mockStorageUsed); - vi.mocked(updateRepoList).mockResolvedValue(undefined); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(undefined); const { req, res } = createMocks({ method: 'POST', @@ -125,7 +119,7 @@ describe('GET /api/cronjob/getStorageUsed', () => { await handler(req, res); expect(res._getStatusCode()).toBe(200); - expect(updateRepoList).toHaveBeenCalledWith([ + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([ { repositoryName: 'repo1', storageUsed: 100 }, { repositoryName: 'repo2', storageUsed: 0 }, ]); diff --git a/pages/api/cronjob/getStorageUsed.ts b/pages/api/cronjob/getStorageUsed.ts index d4a4a4c..37645ee 100644 --- a/pages/api/cronjob/getStorageUsed.ts +++ b/pages/api/cronjob/getStorageUsed.ts @@ -1,5 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; import ApiResponse from '~/helpers/functions/apiResponse'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; @@ -20,7 +20,7 @@ export default async function handler( try { //Check the repoList - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); if (repoList.length === 0) { return ApiResponse.success(res, 'Storage cron executed. No repository to check.'); } @@ -37,7 +37,7 @@ export default async function handler( }; }); - await updateRepoList(updatedRepoList); + await ConfigService.updateRepoList(updatedRepoList); return ApiResponse.success(res, 'Storage cron has been executed.'); } catch (err) { console.log(err); diff --git a/pages/api/repo/add.test.ts b/pages/api/repo/add.test.ts index 1dbc3de..fb75a2a 100644 --- a/pages/api/repo/add.test.ts +++ b/pages/api/repo/add.test.ts @@ -2,7 +2,7 @@ import { getServerSession } from 'next-auth/next'; import { createMocks } from 'node-mocks-http'; import { isSshPubKeyDuplicate, tokenController } from '~/helpers/functions'; import handler from '~/pages/api/repo/add'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; vi.mock('next-auth/next', () => ({ getServerSession: vi.fn(), @@ -13,13 +13,7 @@ vi.mock('~/helpers/functions', () => ({ isSshPubKeyDuplicate: vi.fn(), })); -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), - updateRepoList: vi.fn(), - ShellService: { - createRepo: vi.fn(), - }, -})); +vi.mock('~/services'); describe('POST /api/repo/add', () => { beforeEach(() => { @@ -65,7 +59,9 @@ describe('POST /api/repo/add', () => { it('should return 409 if SSH key is duplicated', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([{ id: 1, sshPublicKey: 'duplicate-key' }]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ + { id: 1, sshPublicKey: 'duplicate-key' }, + ]); vi.mocked(isSshPubKeyDuplicate).mockReturnValue(true); const { req, res } = createMocks({ method: 'POST', @@ -77,7 +73,7 @@ describe('POST /api/repo/add', () => { it('should return 500 if createRepoShell fails', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); vi.mocked(ShellService.createRepo).mockResolvedValue({ stderr: 'Error' }); const { req, res } = createMocks({ method: 'POST', @@ -89,9 +85,9 @@ describe('POST /api/repo/add', () => { it('should successfully create a repository with a session', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); vi.mocked(ShellService.createRepo).mockResolvedValue({ stdout: 'new-repo' }); - vi.mocked(updateRepoList).mockResolvedValue(true); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(true); const { req, res } = createMocks({ method: 'POST', body: { alias: 'repo1', sshPublicKey: 'valid-key', storageSize: 10 }, @@ -103,9 +99,9 @@ describe('POST /api/repo/add', () => { it('should add missing optional properties with default values and update repo list correctly', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); vi.mocked(ShellService.createRepo).mockResolvedValue({ stdout: 'new-repo' }); - vi.mocked(updateRepoList).mockResolvedValue(true); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(true); const { req, res } = createMocks({ method: 'POST', @@ -117,7 +113,7 @@ describe('POST /api/repo/add', () => { expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ id: 0, repositoryName: 'new-repo' }); - expect(updateRepoList).toHaveBeenCalledWith( + expect(ConfigService.updateRepoList).toHaveBeenCalledWith( [ { id: 0, @@ -142,7 +138,7 @@ describe('POST /api/repo/add', () => { it('should assign the correct ID based on existing repositories', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 0, alias: 'repo0', @@ -179,7 +175,7 @@ describe('POST /api/repo/add', () => { ]); vi.mocked(ShellService.createRepo).mockResolvedValue({ stdout: 'new-repo' }); - vi.mocked(updateRepoList).mockResolvedValue(true); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(true); const { req, res } = createMocks({ method: 'POST', @@ -191,7 +187,7 @@ describe('POST /api/repo/add', () => { expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ id: 4, repositoryName: 'new-repo' }); - expect(updateRepoList).toHaveBeenCalledWith( + expect(ConfigService.updateRepoList).toHaveBeenCalledWith( [ { id: 0, diff --git a/pages/api/repo/add.ts b/pages/api/repo/add.ts index 59fffac..9c8f41f 100644 --- a/pages/api/repo/add.ts +++ b/pages/api/repo/add.ts @@ -5,7 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import ApiResponse from '~/helpers/functions/apiResponse'; import { Repository } from '~/types/domain/config.types'; import { getUnixTime } from 'date-fns'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; export default async function handler( req: NextApiRequest & { body: Partial }, @@ -48,7 +48,7 @@ export default async function handler( try { const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = req.body; - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); if (sshPublicKey && isSshPubKeyDuplicate(sshPublicKey, repoList)) { return res.status(409).json({ @@ -85,7 +85,7 @@ export default async function handler( newRepo.repositoryName = stdout.trim(); const updatedRepoList = [...repoList, newRepo]; - await updateRepoList(updatedRepoList, true); + await ConfigService.updateRepoList(updatedRepoList, true); return res.status(200).json({ id: newRepo.id, repositoryName: newRepo.repositoryName }); } catch (error) { diff --git a/pages/api/repo/id/[slug]/delete.test.ts b/pages/api/repo/id/[slug]/delete.test.ts index accb682..920b708 100644 --- a/pages/api/repo/id/[slug]/delete.test.ts +++ b/pages/api/repo/id/[slug]/delete.test.ts @@ -1,7 +1,7 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/repo/id/[slug]/delete'; import { getServerSession } from 'next-auth/next'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; import { tokenController } from '~/helpers/functions'; vi.mock('next-auth/next'); @@ -9,13 +9,7 @@ vi.mock('~/helpers/functions', () => ({ tokenController: vi.fn(), })); -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), - updateRepoList: vi.fn(), - ShellService: { - deleteRepo: vi.fn(), - }, -})); +vi.mock('~/services'); describe('DELETE /api/repo/id/[slug]/delete', () => { beforeEach(() => { @@ -75,7 +69,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { method: 'DELETE', query: { slug: '123' }, }); - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); await handler(req, res); expect(res._getStatusCode()).toBe(404); expect(res._getJSONData()).toEqual({ @@ -92,7 +86,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { method: 'DELETE', query: { slug: '123' }, }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 123, repositoryName: 'test-repo', @@ -112,7 +106,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { status: 500, message: 'API error, contact the administrator.', }); - expect(updateRepoList).not.toHaveBeenCalled(); + expect(ConfigService.updateRepoList).not.toHaveBeenCalled(); }); it('should delete the repository and return 200 on success with a session', async () => { @@ -123,7 +117,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { method: 'DELETE', query: { slug: '1234' }, }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 1234, repositoryName: 'test-repo', @@ -137,14 +131,14 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { }, ]); vi.mocked(ShellService.deleteRepo).mockResolvedValue({ stderr: null }); - vi.mocked(updateRepoList).mockResolvedValue(); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(); await handler(req, res); expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ status: 200, message: 'Repository test-repo deleted', }); - expect(updateRepoList).toHaveBeenCalledWith([], true); + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([], true); }); it('should delete the repository and return 200 on success with an API key', async () => { @@ -162,7 +156,7 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { authorization: 'Bearer API_KEY', }, }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 12345, repositoryName: 'test-repo2', @@ -176,14 +170,14 @@ describe('DELETE /api/repo/id/[slug]/delete', () => { }, ]); vi.mocked(ShellService.deleteRepo).mockResolvedValue({ stdout: 'delete' }); - vi.mocked(updateRepoList).mockResolvedValue(); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(); await handler(req, res); expect(res._getStatusCode()).toBe(200); expect(res._getJSONData()).toEqual({ status: 200, message: 'Repository test-repo2 deleted', }); - expect(updateRepoList).toHaveBeenCalledWith([], true); + expect(ConfigService.updateRepoList).toHaveBeenCalledWith([], true); }); it('should return 401 if the API key is invalid', async () => { diff --git a/pages/api/repo/id/[slug]/delete.ts b/pages/api/repo/id/[slug]/delete.ts index db929a5..d40325e 100644 --- a/pages/api/repo/id/[slug]/delete.ts +++ b/pages/api/repo/id/[slug]/delete.ts @@ -1,7 +1,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { getServerSession } from 'next-auth/next'; import { tokenController } from '~/helpers/functions'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; import ApiResponse from '~/helpers/functions/apiResponse'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; @@ -40,7 +40,7 @@ export default async function handler( } try { - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); const slug = req.query.slug; if (!slug || Array.isArray(slug)) { @@ -61,7 +61,7 @@ export default async function handler( const updatedRepoList = repoList.filter((repo) => repo.id !== parseInt(slug, 10)); - await updateRepoList(updatedRepoList, true); + await ConfigService.updateRepoList(updatedRepoList, true); return ApiResponse.success(res, `Repository ${repoList[indexToDelete].repositoryName} deleted`); } catch (error) { console.log(error); diff --git a/pages/api/repo/id/[slug]/edit.test.ts b/pages/api/repo/id/[slug]/edit.test.ts index 4eec1e5..137d8bf 100644 --- a/pages/api/repo/id/[slug]/edit.test.ts +++ b/pages/api/repo/id/[slug]/edit.test.ts @@ -2,7 +2,7 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/repo/id/[slug]/edit'; import { getServerSession } from 'next-auth/next'; import { tokenController, isSshPubKeyDuplicate } from '~/helpers/functions'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; vi.mock('next-auth/next'); @@ -11,13 +11,7 @@ vi.mock('~/helpers/functions', () => ({ isSshPubKeyDuplicate: vi.fn(), })); -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), - updateRepoList: vi.fn(), - ShellService: { - updateRepo: vi.fn(), - }, -})); +vi.mock('~/services'); describe('PATCH /api/repo/id/[slug]/edit', () => { beforeEach(() => { @@ -74,7 +68,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { it('should return 404 if repository is not found', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); const { req, res } = createMocks({ method: 'PATCH', query: { slug: '123' } }); await handler(req, res); expect(res._getStatusCode()).toBe(404); @@ -82,7 +76,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { it('should return 409 if SSH key is duplicated', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 123, repositoryName: 'test-repo', @@ -108,7 +102,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { it('should return 500 if updateRepoShell fails', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 123, repositoryName: 'test-repo', @@ -134,7 +128,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { it('should successfully update repository with a session', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 123, repositoryName: 'test-repo', @@ -149,7 +143,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { }, ]); vi.mocked(ShellService.updateRepo).mockResolvedValue({ stderr: '', stdout: '' }); - vi.mocked(updateRepoList).mockResolvedValue(); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PATCH', query: { slug: '123' }, @@ -168,7 +162,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { delete: false, read: false, }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 456, repositoryName: 'repo-key', @@ -183,7 +177,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { }, ]); vi.mocked(ShellService.updateRepo).mockResolvedValue({ stderr: null }); - vi.mocked(updateRepoList).mockResolvedValue(); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PATCH', query: { slug: '456' }, @@ -197,7 +191,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { it('should only update the provided fields, keep the rest unchanged and history the modification.', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([ + vi.mocked(ConfigService.getRepoList).mockResolvedValue([ { id: 123, repositoryName: 'test-repo', @@ -212,7 +206,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { }, ]); vi.mocked(ShellService.updateRepo).mockResolvedValue({ stderr: null }); - vi.mocked(updateRepoList).mockResolvedValue(); + vi.mocked(ConfigService.updateRepoList).mockResolvedValue(); const { req, res } = createMocks({ method: 'PATCH', query: { slug: '123' }, @@ -225,7 +219,7 @@ describe('PATCH /api/repo/id/[slug]/edit', () => { }, }); await handler(req, res); - expect(updateRepoList).toHaveBeenCalledWith( + expect(ConfigService.updateRepoList).toHaveBeenCalledWith( [ { id: 123, diff --git a/pages/api/repo/id/[slug]/edit.ts b/pages/api/repo/id/[slug]/edit.ts index b2693f0..6b35f20 100644 --- a/pages/api/repo/id/[slug]/edit.ts +++ b/pages/api/repo/id/[slug]/edit.ts @@ -4,7 +4,7 @@ import { tokenController, isSshPubKeyDuplicate } from '~/helpers/functions'; import { NextApiRequest, NextApiResponse } from 'next'; import ApiResponse from '~/helpers/functions/apiResponse'; import { Repository } from '~/types/domain/config.types'; -import { getRepoList, updateRepoList, ShellService } from '~/services'; +import { ConfigService, ShellService } from '~/services'; export default async function handler( req: NextApiRequest & { body: Partial }, @@ -48,7 +48,7 @@ export default async function handler( const { alias, sshPublicKey, storageSize, comment, alert, lanCommand, appendOnlyMode } = req.body; const slug = req.query.slug; - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); const repoId = parseInt(slug as string, 10); const repo = repoList.find((repo) => repo.id === repoId); if (!repo) { @@ -86,7 +86,7 @@ export default async function handler( } const updatedRepoList = [...filteredRepoList, updatedRepo]; - await updateRepoList(updatedRepoList, true); + await ConfigService.updateRepoList(updatedRepoList, true); return res.status(200).json({ message: `Repository ${repo.repositoryName} has been edited` }); } catch (error) { diff --git a/pages/api/repo/id/[slug]/index.ts b/pages/api/repo/id/[slug]/index.ts index 897639b..62cdcc8 100644 --- a/pages/api/repo/id/[slug]/index.ts +++ b/pages/api/repo/id/[slug]/index.ts @@ -5,7 +5,7 @@ import { BorgWarehouseApiResponse } from '~/types/api/error.types'; import ApiResponse from '~/helpers/functions/apiResponse'; import { tokenController } from '~/helpers/functions'; import { Repository } from '~/types/domain/config.types'; -import { getRepoList } from '~/services'; +import { ConfigService } from '~/services'; export default async function handler( req: NextApiRequest, @@ -36,7 +36,7 @@ export default async function handler( } try { - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); const slug = req.query.slug; if (!slug || Array.isArray(slug)) { diff --git a/pages/api/repo/id/[slug]/repoIndex.test.ts b/pages/api/repo/id/[slug]/repoIndex.test.ts index ef99fa8..58c1b40 100644 --- a/pages/api/repo/id/[slug]/repoIndex.test.ts +++ b/pages/api/repo/id/[slug]/repoIndex.test.ts @@ -2,7 +2,7 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/repo/id/[slug]'; import { getServerSession } from 'next-auth/next'; import { tokenController } from '~/helpers/functions'; -import { getRepoList } from '~/services'; +import { ConfigService } from '~/services'; import { Repository } from '~/types/domain/config.types'; vi.mock('next-auth/next', () => ({ @@ -13,9 +13,7 @@ vi.mock('~/helpers/functions', () => ({ tokenController: vi.fn(), })); -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), -})); +vi.mock('~/services'); const mockRepoList: Repository[] = [ { @@ -100,7 +98,7 @@ describe('GET /api/repo/id/[slug]', () => { it('should return 404 if repository is not found', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue([]); + vi.mocked(ConfigService.getRepoList).mockResolvedValue([]); const { req, res } = createMocks({ method: 'GET', query: { slug: '3' } }); await handler(req, res); expect(res._getStatusCode()).toBe(404); @@ -108,7 +106,7 @@ describe('GET /api/repo/id/[slug]', () => { it('should return 200 and the repository data if found', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue(mockRepoList); + vi.mocked(ConfigService.getRepoList).mockResolvedValue(mockRepoList); const { req, res } = createMocks({ method: 'GET', query: { slug: '1' } }); await handler(req, res); expect(res._getStatusCode()).toBe(200); diff --git a/pages/api/repo/index.ts b/pages/api/repo/index.ts index c8a1b64..1bbfdc6 100644 --- a/pages/api/repo/index.ts +++ b/pages/api/repo/index.ts @@ -4,7 +4,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { BorgWarehouseApiResponse } from '~/types/api/error.types'; import ApiResponse from '~/helpers/functions/apiResponse'; import { tokenController } from '~/helpers/functions'; -import { getRepoList } from '~/services'; +import { ConfigService } from '~/services'; import { Repository } from '~/types/domain/config.types'; export default async function handler( @@ -36,7 +36,7 @@ export default async function handler( } try { - const repoList = await getRepoList(); + const repoList = await ConfigService.getRepoList(); return res.status(200).json({ repoList }); } catch (error) { diff --git a/pages/api/repo/repoListIndex.test.ts b/pages/api/repo/repoListIndex.test.ts index d4c4ac4..ed2434b 100644 --- a/pages/api/repo/repoListIndex.test.ts +++ b/pages/api/repo/repoListIndex.test.ts @@ -2,7 +2,7 @@ import { createMocks } from 'node-mocks-http'; import handler from '~/pages/api/repo'; import { getServerSession } from 'next-auth/next'; import { tokenController } from '~/helpers/functions'; -import { getRepoList } from '~/services'; +import { ConfigService } from '~/services'; import { Repository } from '~/types/domain/config.types'; vi.mock('next-auth/next', () => ({ @@ -13,9 +13,7 @@ vi.mock('~/helpers/functions', () => ({ tokenController: vi.fn(), })); -vi.mock('~/services', () => ({ - getRepoList: vi.fn(), -})); +vi.mock('~/services'); const mockRepoList: Repository[] = [ { @@ -93,7 +91,7 @@ describe('GET /api/repo/id/[slug]', () => { it('should return 200 and the repoList data if found', async () => { vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'USER' } }); - vi.mocked(getRepoList).mockResolvedValue(mockRepoList); + vi.mocked(ConfigService.getRepoList).mockResolvedValue(mockRepoList); const { req, res } = createMocks({ method: 'GET' }); await handler(req, res); expect(res._getStatusCode()).toBe(200); diff --git a/services/__mocks__/services.ts b/services/__mocks__/services.ts new file mode 100644 index 0000000..561bcb4 --- /dev/null +++ b/services/__mocks__/services.ts @@ -0,0 +1,14 @@ +export const ShellService = { + deleteRepo: vi.fn(), + updateRepo: vi.fn(), + createRepo: vi.fn(), + getLastSaveList: vi.fn(), + getStorageUsed: vi.fn(), +}; + +export const ConfigService = { + getUsersList: vi.fn(), + getRepoList: vi.fn(), + updateUsersList: vi.fn(), + updateRepoList: vi.fn(), +}; diff --git a/services/config.service.ts b/services/config.service.ts index 8e694b9..da8e2fc 100644 --- a/services/config.service.ts +++ b/services/config.service.ts @@ -1,9 +1,9 @@ import { Low } from 'lowdb'; +import { promises as fs } from 'fs'; import { JSONFile } from 'lowdb/node'; import path from 'path'; import { Mutex } from 'async-mutex'; import { BorgWarehouseUser, Repository } from '~/types/domain/config.types'; -import repoHistory from './history.service'; const jsonDirectory = path.join(process.cwd(), '/config'); const usersDbPath = path.join(jsonDirectory, 'users.json'); @@ -20,53 +20,87 @@ const repoDb = new Low(repoAdapter, []); const usersMutex = new Mutex(); const repoMutex = new Mutex(); -// User management -export const getUsersList = async (): Promise => { - try { - await usersMutex.runExclusive(async () => { - await usersDb.read(); - }); - return usersDb.data; - } catch (error) { - console.log('Error reading users.json:', error); - return []; - } +export const ConfigService = { + getUsersList: async (): Promise => { + try { + await usersMutex.runExclusive(async () => { + await usersDb.read(); + }); + return usersDb.data; + } catch (error) { + console.log('Error reading users.json:', error); + return []; + } + }, + + updateUsersList: async (usersList: BorgWarehouseUser[]): Promise => { + try { + await usersMutex.runExclusive(async () => { + usersDb.data = usersList; + await usersDb.write(); + }); + } catch (error) { + console.log('Error writing users.json:', error); + } + }, + + getRepoList: async (): Promise => { + try { + await repoMutex.runExclusive(async () => { + await repoDb.read(); + }); + return repoDb.data; + } catch (error) { + console.log('Error reading repo.json:', error); + return []; + } + }, + + updateRepoList: async (repoList: Repository[], history = false): Promise => { + try { + await repoMutex.runExclusive(async () => { + if (history) { + await repoHistory(repoList); + } + repoDb.data = repoList; + await repoDb.write(); + }); + } catch (error) { + console.log('Error writing repo.json:', error); + } + }, }; -export const updateUsersList = async (usersList: BorgWarehouseUser[]): Promise => { +// Repository history management +async function repoHistory(repoList: Repository[]) { try { - await usersMutex.runExclusive(async () => { - usersDb.data = usersList; - await usersDb.write(); - }); - } catch (error) { - console.log('Error writing users.json:', error); - } -}; + const repoHistoryDir = path.join(process.cwd(), '/config/versions'); + const maxBackupCount = parseInt(process.env.MAX_REPO_BACKUP_COUNT ?? '8', 10); + const timestamp = new Date().toISOString(); + const backupDate = timestamp.split('T')[0]; -// Repository management -export const getRepoList = async (): Promise => { - try { - await repoMutex.runExclusive(async () => { - await repoDb.read(); - }); - return repoDb.data; - } catch (error) { - console.log('Error reading repo.json:', error); - return []; - } -}; + //Create the directory if it does not exist + await fs.mkdir(repoHistoryDir, { recursive: true }); -export const updateRepoList = async (repoList: Repository[], history = false): Promise => { - try { - await repoMutex.runExclusive(async () => { - if (history) { - await repoHistory(repoList); + const existingBackups = await fs.readdir(repoHistoryDir); + + if (existingBackups.length >= maxBackupCount) { + existingBackups.sort(); + const backupsToDelete = existingBackups.slice(0, existingBackups.length - maxBackupCount + 1); + for (const backupToDelete of backupsToDelete) { + const backupFilePathToDelete = path.join(repoHistoryDir, backupToDelete); + await fs.unlink(backupFilePathToDelete); } - repoDb.data = repoList; - await repoDb.write(); - }); + } + + const backupFileName = `${backupDate}.log`; + const backupFilePath = path.join(repoHistoryDir, backupFileName); + const jsonData = JSON.stringify(repoList, null, 2); + + const logData = `\n>>>> History of file repo.json at "${timestamp}" <<<<\n${jsonData}\n`; + + await fs.appendFile(backupFilePath, logData); } catch (error) { - console.log('Error writing repo.json:', error); + console.log('An error occurred while saving the repo history :', error); } -}; +} diff --git a/services/history.service.ts b/services/history.service.ts deleted file mode 100644 index 1399ef0..0000000 --- a/services/history.service.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { promises as fs } from 'fs'; -import path from 'path'; -import { Repository } from '~/types/domain/config.types'; - -export default async function repoHistory(repoList: Repository[]) { - try { - const repoHistoryDir = path.join(process.cwd(), '/config/versions'); - const maxBackupCount = parseInt(process.env.MAX_REPO_BACKUP_COUNT ?? '8', 10); - const timestamp = new Date().toISOString(); - const backupDate = timestamp.split('T')[0]; - - //Create the directory if it does not exist - await fs.mkdir(repoHistoryDir, { recursive: true }); - - const existingBackups = await fs.readdir(repoHistoryDir); - - if (existingBackups.length >= maxBackupCount) { - existingBackups.sort(); - const backupsToDelete = existingBackups.slice(0, existingBackups.length - maxBackupCount + 1); - for (const backupToDelete of backupsToDelete) { - const backupFilePathToDelete = path.join(repoHistoryDir, backupToDelete); - await fs.unlink(backupFilePathToDelete); - } - } - - const backupFileName = `${backupDate}.log`; - const backupFilePath = path.join(repoHistoryDir, backupFileName); - const jsonData = JSON.stringify(repoList, null, 2); - - const logData = `\n>>>> History of file repo.json at "${timestamp}" <<<<\n${jsonData}\n`; - - await fs.appendFile(backupFilePath, logData); - } catch (error) { - console.log('An error occurred while saving the repo history :', error); - } -} diff --git a/services/index.ts b/services/index.ts index ac9ff27..1443203 100644 --- a/services/index.ts +++ b/services/index.ts @@ -1,3 +1,2 @@ export * from './config.service'; -export * from './history.service'; export * from './shell.service';