test: apprise, email and wizard API

This commit is contained in:
Ravinou 2025-03-02 14:33:19 +01:00
commit d753df49a0
No known key found for this signature in database
GPG key ID: EEEE670C40F6A4D7
7 changed files with 410 additions and 39 deletions

View file

@ -1,48 +1,45 @@
//Lib
import { authOptions } from '~/pages/api/auth/[...nextauth]';
import { getServerSession } from 'next-auth/next';
import { WizardEnvEnum } from '~/types/domain/config.types';
import { WizardEnvEnum, WizardEnvType } from '~/types/domain/config.types';
import { NextApiRequest, NextApiResponse } from 'next';
import { ErrorResponse } from '~/types/api/error.types';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method == 'GET') {
//AUTHENTICATION
const session = await getServerSession(req, res, authOptions);
if (!session) {
res.status(401).json({ message: 'You must be logged in.' });
return;
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<WizardEnvType | ErrorResponse>
) {
if (req.method !== 'GET') {
return res.status(405);
}
const session = await getServerSession(req, res, authOptions);
if (!session) {
return res.status(401);
}
try {
function getEnvVariable(envName: WizardEnvEnum, defaultValue = '') {
return process.env[envName] || defaultValue;
}
try {
function getEnvVariable(envName: WizardEnvEnum, defaultValue = '') {
return process.env[envName] || defaultValue;
}
const wizardEnv: WizardEnvType = {
UNIX_USER: getEnvVariable(WizardEnvEnum.UNIX_USER, 'borgwarehouse'),
FQDN: getEnvVariable(WizardEnvEnum.FQDN, 'localhost'),
SSH_SERVER_PORT: getEnvVariable(WizardEnvEnum.SSH_SERVER_PORT, '22'),
FQDN_LAN: getEnvVariable(WizardEnvEnum.FQDN_LAN),
SSH_SERVER_PORT_LAN: getEnvVariable(WizardEnvEnum.SSH_SERVER_PORT_LAN),
SSH_SERVER_FINGERPRINT_RSA: getEnvVariable(WizardEnvEnum.SSH_SERVER_FINGERPRINT_RSA),
SSH_SERVER_FINGERPRINT_ED25519: getEnvVariable(WizardEnvEnum.SSH_SERVER_FINGERPRINT_ED25519),
SSH_SERVER_FINGERPRINT_ECDSA: getEnvVariable(WizardEnvEnum.SSH_SERVER_FINGERPRINT_ECDSA),
HIDE_SSH_PORT: getEnvVariable(WizardEnvEnum.HIDE_SSH_PORT, 'false'),
DISABLE_INTEGRATIONS: getEnvVariable(WizardEnvEnum.DISABLE_INTEGRATIONS, 'false'),
DISABLE_DELETE_REPO: getEnvVariable(WizardEnvEnum.DISABLE_DELETE_REPO, 'false'),
};
const wizardEnv = {
UNIX_USER: getEnvVariable(WizardEnvEnum.UNIX_USER, 'borgwarehouse'),
FQDN: getEnvVariable(WizardEnvEnum.FQDN, 'localhost'),
SSH_SERVER_PORT: getEnvVariable(WizardEnvEnum.SSH_SERVER_PORT, '22'),
FQDN_LAN: getEnvVariable(WizardEnvEnum.FQDN_LAN),
SSH_SERVER_PORT_LAN: getEnvVariable(WizardEnvEnum.SSH_SERVER_PORT_LAN),
SSH_SERVER_FINGERPRINT_RSA: getEnvVariable(WizardEnvEnum.SSH_SERVER_FINGERPRINT_RSA),
SSH_SERVER_FINGERPRINT_ED25519: getEnvVariable(
WizardEnvEnum.SSH_SERVER_FINGERPRINT_ED25519
),
SSH_SERVER_FINGERPRINT_ECDSA: getEnvVariable(WizardEnvEnum.SSH_SERVER_FINGERPRINT_ECDSA),
HIDE_SSH_PORT: getEnvVariable(WizardEnvEnum.HIDE_SSH_PORT, 'false'),
DISABLE_INTEGRATIONS: getEnvVariable(WizardEnvEnum.DISABLE_INTEGRATIONS, 'false'),
};
res.status(200).json({ wizardEnv });
return;
} catch (error) {
console.log(error);
res.status(500).json({
message: 'API error, contact the administrator',
});
return;
}
} else {
res.status(405).json({ message: 'Bad request on API' });
res.status(200).json(wizardEnv);
return;
} catch (error) {
console.log(error);
return res.status(500);
}
}

View file

@ -0,0 +1,76 @@
import { createMocks } from 'node-mocks-http';
import handler from '~/pages/api/account/getAppriseAlert';
import { getServerSession } from 'next-auth/next';
import { promises as fs } from 'fs';
import path from 'path';
jest.mock('next-auth/next');
jest.mock('fs', () => ({
promises: {
readFile: jest.fn(),
},
}));
describe('Get Apprise Alert API', () => {
it('should return 405 if the method is not GET', async () => {
const { req, res } = createMocks({ method: 'POST' });
await handler(req, res);
expect(res._getStatusCode()).toBe(405);
});
it('should return 401 if the user is not authenticated', async () => {
(getServerSession as jest.Mock).mockResolvedValue(null);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(401);
expect(res._getJSONData()).toEqual({ message: 'You must be logged in.' });
});
it('should return 400 if the user does not exist', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'nonexistent' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([{ username: 'testuser', appriseAlert: true }])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(res._getJSONData()).toEqual({
message: 'User is incorrect. Please, logout to update your session.',
});
});
it('should return appriseAlert value if the user exists', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([{ username: 'testuser', appriseAlert: true }])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(res._getJSONData()).toEqual({ appriseAlert: true });
});
it('should return 500 if there is an error reading the file', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(500);
expect(res._getJSONData()).toEqual({ status: 500, message: 'No such file or directory' });
});
});

View file

@ -0,0 +1,91 @@
import { createMocks } from 'node-mocks-http';
import handler from '~/pages/api/account/getAppriseMode';
import { getServerSession } from 'next-auth/next';
import { promises as fs } from 'fs';
import path from 'path';
jest.mock('next-auth/next');
jest.mock('fs', () => ({
promises: {
readFile: jest.fn(),
},
}));
describe('Get Apprise Mode API', () => {
it('should return 405 if the method is not GET', async () => {
const { req, res } = createMocks({ method: 'POST' });
await handler(req, res);
expect(res._getStatusCode()).toBe(405);
});
it('should return 401 if the user is not authenticated', async () => {
(getServerSession as jest.Mock).mockResolvedValue(null);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(401);
expect(res._getJSONData()).toEqual({ message: 'You must be logged in.' });
});
it('should return 400 if the user does not exist', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'nonexistent' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([
{
username: 'testuser',
appriseMode: 'stateless',
appriseStatelessURL: 'https://example.com',
},
])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(res._getJSONData()).toEqual({
message: 'User is incorrect. Please, logout to update your session.',
});
});
it('should return appriseMode and appriseStatelessURL if the user exists', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([
{
username: 'testuser',
appriseMode: 'stateless',
appriseStatelessURL: 'https://example.com',
},
])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(res._getJSONData()).toEqual({
appriseMode: 'stateless',
appriseStatelessURL: 'https://example.com',
});
});
it('should return 500 if there is an error reading the file', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(500);
expect(res._getJSONData()).toEqual({ status: 500, message: 'No such file or directory' });
});
});

View file

@ -0,0 +1,78 @@
import { createMocks } from 'node-mocks-http';
import handler from '~/pages/api/account/getAppriseServices';
import { getServerSession } from 'next-auth/next';
import { promises as fs } from 'fs';
import path from 'path';
jest.mock('next-auth/next');
jest.mock('fs', () => ({
promises: {
readFile: jest.fn(),
},
}));
describe('Get Apprise Services API', () => {
it('should return 405 if the method is not GET', async () => {
const { req, res } = createMocks({ method: 'POST' });
await handler(req, res);
expect(res._getStatusCode()).toBe(405);
});
it('should return 401 if the user is not authenticated', async () => {
(getServerSession as jest.Mock).mockResolvedValue(null);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(401);
expect(res._getJSONData()).toEqual({ message: 'You must be logged in.' });
});
it('should return 400 if the user does not exist', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'nonexistent' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([{ username: 'testuser', appriseServices: ['service1', 'service2'] }])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(res._getJSONData()).toEqual({
message: 'User is incorrect. Please, logout to update your session.',
});
});
it('should return appriseServices if the user exists', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([{ username: 'testuser', appriseServices: ['service1', 'service2'] }])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(res._getJSONData()).toEqual({
appriseServices: ['service1', 'service2'],
});
});
it('should return 500 if there is an error reading the file', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(500);
expect(res._getJSONData()).toEqual({ status: 500, message: 'No such file or directory' });
});
});

View file

@ -0,0 +1,78 @@
import { createMocks } from 'node-mocks-http';
import handler from '~/pages/api/account/getEmailAlert';
import { getServerSession } from 'next-auth/next';
import { promises as fs } from 'fs';
import path from 'path';
jest.mock('next-auth/next');
jest.mock('fs', () => ({
promises: {
readFile: jest.fn(),
},
}));
describe('Get Email Alert API', () => {
it('should return 405 if the method is not GET', async () => {
const { req, res } = createMocks({ method: 'POST' });
await handler(req, res);
expect(res._getStatusCode()).toBe(405);
});
it('should return 401 if the user is not authenticated', async () => {
(getServerSession as jest.Mock).mockResolvedValue(null);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(401);
expect(res._getJSONData()).toEqual({ message: 'You must be logged in.' });
});
it('should return 400 if the user does not exist', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'nonexistent' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([{ username: 'testuser', emailAlert: true }])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(res._getJSONData()).toEqual({
message: 'User is incorrect. Please, logout to update your session.',
});
});
it('should return emailAlert if the user exists', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockResolvedValue(
JSON.stringify([{ username: 'testuser', emailAlert: true }])
);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(res._getJSONData()).toEqual({
emailAlert: true,
});
});
it('should return 500 if there is an error reading the file', async () => {
(getServerSession as jest.Mock).mockResolvedValue({
user: { name: 'testuser' },
});
(fs.readFile as jest.Mock).mockRejectedValue({ code: 'ENOENT' });
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(500);
expect(res._getJSONData()).toEqual({ status: 500, message: 'No such file or directory' });
});
});

View file

@ -0,0 +1,51 @@
import { createMocks } from 'node-mocks-http';
import handler from '~/pages/api/account/getWizardEnv';
import { getServerSession } from 'next-auth/next';
import { WizardEnvEnum } from '~/types/domain/config.types';
jest.mock('next-auth/next');
describe('Get Wizard Env API', () => {
it('should return 405 if the method is not GET', async () => {
const { req, res } = createMocks({ method: 'POST' });
await handler(req, res);
expect(res._getStatusCode()).toBe(405);
});
it('should return 401 if the user is not authenticated', async () => {
(getServerSession as jest.Mock).mockResolvedValue(null);
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(401);
});
it('should return 200 with wizardEnv if the user is authenticated', async () => {
(getServerSession as jest.Mock).mockResolvedValue({ user: { name: 'testuser' } });
process.env.UNIX_USER = 'borgwarehouse';
process.env.FQDN = 'localhost';
process.env.SSH_SERVER_PORT = '22';
process.env.HIDE_SSH_PORT = 'false';
process.env.DISABLE_INTEGRATIONS = 'false';
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(res._getJSONData()).toEqual({
wizardEnv: {
UNIX_USER: 'borgwarehouse',
FQDN: 'localhost',
SSH_SERVER_PORT: '22',
FQDN_LAN: '',
SSH_SERVER_PORT_LAN: '',
SSH_SERVER_FINGERPRINT_RSA: '',
SSH_SERVER_FINGERPRINT_ED25519: '',
SSH_SERVER_FINGERPRINT_ECDSA: '',
HIDE_SSH_PORT: 'false',
DISABLE_INTEGRATIONS: 'false',
DISABLE_DELETE_REPO: 'false',
},
});
});
});

View file

@ -2,7 +2,7 @@ export type EmailSettingDTO = {
email: string;
};
export type UserSettingDTO = {
export type UsernameSettingDTO = {
username: string;
};