refactor: config service

This commit is contained in:
Ravinou 2025-04-08 23:23:20 +02:00
commit 3815109958
No known key found for this signature in database
GPG key ID: EEEE670C40F6A4D7
45 changed files with 322 additions and 371 deletions

View file

@ -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);

View file

@ -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();
});

View file

@ -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);

View file

@ -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' });

View file

@ -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);

View file

@ -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();
});

View file

@ -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);

View file

@ -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();
});

View file

@ -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);

View file

@ -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.' });

View file

@ -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 () => {

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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',

View file

@ -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);

View file

@ -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',

View file

@ -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);

View file

@ -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',

View file

@ -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);

View file

@ -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',

View file

@ -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);

View file

@ -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',

View file

@ -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) {

View file

@ -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',

View file

@ -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) {

View file

@ -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<RequestInternal>, 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());

View file

@ -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',

View file

@ -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);

View file

@ -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 },
]);

View file

@ -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);

View file

@ -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,

View file

@ -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<Repository> },
@ -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) {

View file

@ -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 () => {

View file

@ -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);

View file

@ -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,

View file

@ -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<Repository> },
@ -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) {

View file

@ -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)) {

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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(),
};

View file

@ -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<BorgWarehouseUser[]> => {
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<BorgWarehouseUser[]> => {
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<void> => {
try {
await usersMutex.runExclusive(async () => {
usersDb.data = usersList;
await usersDb.write();
});
} catch (error) {
console.log('Error writing users.json:', error);
}
},
getRepoList: async (): Promise<Repository[]> => {
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<void> => {
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<void> => {
// 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<Repository[]> => {
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<void> => {
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);
}
};
}

View file

@ -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);
}
}

View file

@ -1,3 +1,2 @@
export * from './config.service';
export * from './history.service';
export * from './shell.service';