diff --git a/pages/api/account/getAppriseAlert.test.ts b/pages/api/account/getAppriseAlert.test.ts deleted file mode 100644 index 62e335a..0000000 --- a/pages/api/account/getAppriseAlert.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { getServerSession } from 'next-auth/next'; -import { createMocks } from 'node-mocks-http'; -import { ConfigService } from '~/services'; -import handler from '~/pages/api/account/getAppriseAlert'; - -vi.mock('next-auth/next'); -vi.mock('~/services'); - -describe('Get Apprise Alert API', () => { - beforeEach(() => { - vi.clearAllMocks(); - vi.spyOn(console, 'log').mockImplementation(() => {}); - }); - - 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 () => { - vi.mocked(getServerSession).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 () => { - vi.mocked(getServerSession).mockResolvedValue({ - user: { name: 'nonexistent' }, - }); - - vi.mocked(ConfigService.getUsersList).mockResolvedValue([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - 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 () => { - vi.mocked(getServerSession).mockResolvedValue({ - user: { name: 'testuser' }, - }); - - vi.mocked(ConfigService.getUsersList).mockResolvedValue([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - 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 () => { - vi.mocked(getServerSession).mockResolvedValue({ - user: { name: 'testuser' }, - }); - - vi.mocked(ConfigService.getUsersList).mockImplementation(() => { - throw new Error(); - }); - - const { req, res } = createMocks({ method: 'GET' }); - await handler(req, res); - - expect(res._getStatusCode()).toBe(500); - expect(res._getJSONData()).toEqual({ - status: 500, - message: 'API error, contact the administrator', - }); - }); -}); diff --git a/pages/api/account/getAppriseAlert.ts b/pages/api/account/getAppriseAlert.ts deleted file mode 100644 index b66a477..0000000 --- a/pages/api/account/getAppriseAlert.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next'; -import { getServerSession } from 'next-auth/next'; -import { ConfigService } from '~/services'; -import { ErrorResponse, AppriseAlertResponse } from '~/types'; -import { authOptions } from '../auth/[...nextauth]'; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method !== 'GET') { - res.status(405).json({ message: 'Bad request on API' }); - return; - } - - //Verify that the user is logged in. - const session = await getServerSession(req, res, authOptions); - if (!session) { - res.status(401).json({ message: 'You must be logged in.' }); - return; - } - - try { - const usersList = await ConfigService.getUsersList(); - - //Verify that the user of the session exists - const user = usersList.find((u) => u.username === session.user?.name); - if (!user) { - res.status(400).json({ - message: 'User is incorrect. Please, logout to update your session.', - }); - return; - } - - res.status(200).json({ appriseAlert: user.appriseAlert }); - } catch (error: any) { - console.log(error); - const errorMessage = - error.code === 'ENOENT' - ? 'No such file or directory' - : 'API error, contact the administrator'; - - res.status(500).json({ status: 500, message: errorMessage }); - } -} diff --git a/pages/api/account/getAppriseMode.ts b/pages/api/account/getAppriseMode.ts deleted file mode 100644 index 93666e7..0000000 --- a/pages/api/account/getAppriseMode.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next'; -import { getServerSession } from 'next-auth/next'; -import { ConfigService } from '~/services'; -import { authOptions } from '../auth/[...nextauth]'; -import { AppriseModeDTO, ErrorResponse } from '~/types'; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method !== 'GET') { - res.status(405).json({ message: 'Bad request on API' }); - return; - } - //Verify that the user is logged in. - const session = await getServerSession(req, res, authOptions); - if (!session) { - res.status(401).json({ message: 'You must be logged in.' }); - return; - } - try { - const usersList = await ConfigService.getUsersList(); - - //Verify that the user of the session exists - const user = usersList.find((u) => u.username === session.user?.name); - if (!user) { - res.status(400).json({ - message: 'User is incorrect. Please, logout to update your session.', - }); - return; - } - res.status(200).json({ - appriseMode: user.appriseMode, - appriseStatelessURL: user.appriseStatelessURL, - }); - } catch (error: any) { - console.log(error); - const errorMessage = - error.code === 'ENOENT' - ? 'No such file or directory' - : 'API error, contact the administrator'; - - res.status(500).json({ status: 500, message: errorMessage }); - } -} diff --git a/pages/api/account/getAppriseServices.test.ts b/pages/api/account/getAppriseServices.test.ts deleted file mode 100644 index af6b78c..0000000 --- a/pages/api/account/getAppriseServices.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { getServerSession } from 'next-auth/next'; -import { createMocks } from 'node-mocks-http'; -import { ConfigService } from '~/services'; -import handler from '~/pages/api/account/getAppriseServices'; - -vi.mock('next-auth/next'); -vi.mock('~/services'); - -describe('Get Apprise Services API', () => { - beforeEach(() => { - vi.clearAllMocks(); - vi.spyOn(console, 'log').mockImplementation(() => {}); - }); - - 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 () => { - vi.mocked(getServerSession).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 () => { - vi.mocked(getServerSession).mockResolvedValue({ - user: { name: 'nonexistent' }, - }); - - vi.mocked(ConfigService.getUsersList).mockResolvedValue([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - 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 () => { - vi.mocked(getServerSession).mockResolvedValue({ - user: { name: 'testuser' }, - }); - - vi.mocked(ConfigService.getUsersList).mockResolvedValue([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - 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 () => { - vi.mocked(getServerSession).mockResolvedValue({ - user: { name: 'testuser' }, - }); - - vi.mocked(ConfigService.getUsersList).mockImplementation(() => { - throw new Error(); - }); - - const { req, res } = createMocks({ method: 'GET' }); - await handler(req, res); - - expect(res._getStatusCode()).toBe(500); - expect(res._getJSONData()).toEqual({ - status: 500, - message: 'API error, contact the administrator', - }); - }); -}); diff --git a/pages/api/account/getAppriseServices.ts b/pages/api/account/getAppriseServices.ts deleted file mode 100644 index 00ff928..0000000 --- a/pages/api/account/getAppriseServices.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next'; -import { getServerSession } from 'next-auth/next'; -import { ConfigService } from '~/services'; -import { authOptions } from '../auth/[...nextauth]'; -import { AppriseServicesDTO, ErrorResponse } from '~/types'; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse -) { - if (req.method !== 'GET') { - res.status(405).json({ message: 'Bad request on API' }); - return; - } - //Verify that the user is logged in. - const session = await getServerSession(req, res, authOptions); - if (!session) { - res.status(401).json({ message: 'You must be logged in.' }); - return; - } - try { - const usersList = await ConfigService.getUsersList(); - - //Verify that the user of the session exists - const user = usersList.find((u) => u.username === session.user?.name); - if (!user) { - res.status(400).json({ - message: 'User is incorrect. Please, logout to update your session.', - }); - return; - } - - res.status(200).json({ - appriseServices: user.appriseServices, - }); - } catch (error: any) { - console.log(error); - const errorMessage = - error.code === 'ENOENT' - ? 'No such file or directory' - : 'API error, contact the administrator'; - - res.status(500).json({ status: 500, message: errorMessage }); - } -} diff --git a/pages/api/account/updateAppriseAlert.ts b/pages/api/account/updateAppriseAlert.ts deleted file mode 100644 index 378870d..0000000 --- a/pages/api/account/updateAppriseAlert.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Imports -import { ConfigService } from '~/services'; -import { authOptions } from '../auth/[...nextauth]'; -import { getServerSession } from 'next-auth/next'; -import { NextApiRequest, NextApiResponse } from 'next'; -import { ErrorResponse, AppriseAlertDTO, AppriseAlertResponse } from '~/types'; - -export default async function handler( - req: NextApiRequest & { body: AppriseAlertDTO }, - res: NextApiResponse -) { - if (req.method !== 'PUT') { - return res.status(405); - } - - const session = await getServerSession(req, res, authOptions); - if (!session) { - return res.status(401); - } - - const { appriseAlert } = req.body; - if (typeof appriseAlert !== 'boolean') { - return res.status(422).json({ message: 'Unexpected data' }); - } - - try { - const usersList = await ConfigService.getUsersList(); - const userIndex = usersList.findIndex((u) => u.username === session.user?.name); - - if (userIndex === -1) { - return res - .status(400) - .json({ message: 'User is incorrect. Please, logout to update your session.' }); - } - - const updatedUsersList = usersList.map((user, index) => - index === userIndex ? { ...user, appriseAlert } : user - ); - - await ConfigService.updateUsersList(updatedUsersList); - return res.status(200).json({ message: 'Successful API send' }); - } catch (error: any) { - console.log(error); - return res.status(500).json({ - status: 500, - message: - error.code === 'ENOENT' - ? 'No such file or directory' - : 'API error, contact the administrator', - }); - } -} diff --git a/pages/api/account/updateAppriseMode.test.ts b/pages/api/account/updateAppriseMode.test.ts deleted file mode 100644 index 8c585aa..0000000 --- a/pages/api/account/updateAppriseMode.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { createMocks } from 'node-mocks-http'; -import handler from '~/pages/api/account/updateAppriseMode'; -import { getServerSession } from 'next-auth/next'; -import { ConfigService } from '~/services'; -import { AppriseModeEnum } from '~/types/domain/config.types'; - -vi.mock('next-auth/next'); -vi.mock('~/services'); - -describe('Apprise Mode API', () => { - it('should return 405 if method is not PUT', async () => { - const { req, res } = createMocks({ method: 'GET' }); - await handler(req, res); - expect(res._getStatusCode()).toBe(405); - }); - - it('should return 401 if not authenticated', async () => { - vi.mocked(getServerSession).mockResolvedValue(null); - - const { req, res } = createMocks({ method: 'PUT' }); - await handler(req, res); - - expect(res._getStatusCode()).toBe(401); - }); - - it('should return 422 if invalid data is provided', async () => { - vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testuser' } }); - - const { req, res } = createMocks({ - method: 'PUT', - body: { appriseMode: 'invalid-mode', appriseStatelessURL: 'https://example.com' }, - }); - - await handler(req, res); - expect(res._getStatusCode()).toBe(422); - }); - - it('should return 400 if user does not exist', async () => { - vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'unknownuser' } }); - vi.mocked(ConfigService.getUsersList).mockResolvedValue([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - appriseMode: AppriseModeEnum.PACKAGE, - }, - ]); - - const { req, res } = createMocks({ - method: 'PUT', - body: { appriseMode: 'stateless', appriseStatelessURL: 'https://example.com' }, - }); - - await handler(req, res); - expect(res._getStatusCode()).toBe(400); - }); - - it('should update user settings and return 200', async () => { - vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testuser' } }); - vi.mocked(ConfigService.getUsersList).mockResolvedValue([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - appriseMode: AppriseModeEnum.PACKAGE, - }, - ]); - vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); - - const { req, res } = createMocks({ - method: 'PUT', - body: { appriseMode: 'stateless', appriseStatelessURL: 'https://example.com' }, - }); - - await handler(req, res); - - expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ - { - id: 1, - username: 'testuser', - password: 'hashedpassword', - roles: ['user'], - email: 'testuser@example.com', - appriseMode: AppriseModeEnum.STATELESS, - appriseStatelessURL: 'https://example.com', - }, - ]); - expect(res._getStatusCode()).toBe(200); - }); -}); diff --git a/pages/api/account/updateAppriseMode.ts b/pages/api/account/updateAppriseMode.ts deleted file mode 100644 index 204a974..0000000 --- a/pages/api/account/updateAppriseMode.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ConfigService } from '~/services'; -import { authOptions } from '../auth/[...nextauth]'; -import { getServerSession } from 'next-auth/next'; -import { NextApiRequest, NextApiResponse } from 'next'; -import { AppriseModeDTO, ErrorResponse } from '~/types'; - -export default async function handler( - req: NextApiRequest & { body: AppriseModeDTO }, - res: NextApiResponse -) { - if (req.method !== 'PUT') { - return res.status(405); - } - - const session = await getServerSession(req, res, authOptions); - if (!session) { - return res.status(401); - } - - const { appriseMode, appriseStatelessURL } = req.body; - - if (!['package', 'stateless'].includes(appriseMode)) { - return res.status(422).json({ message: 'Unexpected data' }); - } - - try { - const usersList = await ConfigService.getUsersList(); - const userIndex = usersList.findIndex((user) => user.username === session.user?.name); - - if (userIndex === -1) { - return res.status(400).json({ - message: 'User is incorrect. Please, logout to update your session.', - }); - } - - const updatedUsersList = usersList.map((user, index) => - index === userIndex ? { ...user, appriseMode, appriseStatelessURL } : user - ); - - await ConfigService.updateUsersList(updatedUsersList); - return res.status(200).json({ message: 'Successful API send' }); - } catch (error: any) { - console.log(error); - return res.status(500).json({ - status: 500, - message: - error.code === 'ENOENT' - ? 'No such file or directory' - : 'API error, contact the administrator', - }); - } -} diff --git a/pages/api/account/updateAppriseServices.ts b/pages/api/account/updateAppriseServices.ts deleted file mode 100644 index 6a06fc0..0000000 --- a/pages/api/account/updateAppriseServices.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { authOptions } from '../auth/[...nextauth]'; -import { getServerSession } from 'next-auth/next'; -import { NextApiRequest, NextApiResponse } from 'next'; -import { ConfigService } from '~/services'; -import { AppriseServicesDTO, ErrorResponse } from '~/types'; - -export default async function handler( - req: NextApiRequest & { body: AppriseServicesDTO }, - res: NextApiResponse -) { - if (req.method !== 'PUT') { - return res.status(405); - } - - const session = await getServerSession(req, res, authOptions); - if (!session) { - return res.status(401); - } - - const { appriseURLs } = req.body; - - try { - const usersList = await ConfigService.getUsersList(); - const userIndex = usersList.findIndex((user) => user.username === session.user?.name); - - if (userIndex === -1) { - return res.status(400).json({ - message: 'User is incorrect. Please, logout to update your session.', - }); - } - - //Build the services URLs list from form - const appriseURLsArray = appriseURLs - .replace(/ /g, '') - .split('\n') - .filter((el: string) => el != ''); - - const updatedUsersList = usersList.map((user, index) => - index === userIndex ? { ...user, appriseServices: appriseURLsArray } : user - ); - - await ConfigService.updateUsersList(updatedUsersList); - return res.status(200).json({ message: 'Successful API send' }); - } catch (error: any) { - console.log(error); - return res.status(500).json({ - status: 500, - message: - error.code === 'ENOENT' - ? 'No such file or directory' - : 'API error, contact the administrator', - }); - } -} diff --git a/pages/api/cronjob/checkStatus.test.ts b/pages/api/cronjob/check-status.test.ts similarity index 99% rename from pages/api/cronjob/checkStatus.test.ts rename to pages/api/cronjob/check-status.test.ts index 6078efe..5d0dc2d 100644 --- a/pages/api/cronjob/checkStatus.test.ts +++ b/pages/api/cronjob/check-status.test.ts @@ -1,5 +1,5 @@ import { createMocks } from 'node-mocks-http'; -import handler from '~/pages/api/cronjob/checkStatus'; +import handler from '~/pages/api/cronjob/check-status'; import { ConfigService, NotifService, ShellService } from '~/services'; import { AppriseModeEnum } from '~/types/domain/config.types'; diff --git a/pages/api/cronjob/checkStatus.ts b/pages/api/cronjob/check-status.ts similarity index 100% rename from pages/api/cronjob/checkStatus.ts rename to pages/api/cronjob/check-status.ts diff --git a/pages/api/cronjob/getStorageUsed.test.ts b/pages/api/cronjob/check-storage.test.ts similarity index 98% rename from pages/api/cronjob/getStorageUsed.test.ts rename to pages/api/cronjob/check-storage.test.ts index e226d34..0660905 100644 --- a/pages/api/cronjob/getStorageUsed.test.ts +++ b/pages/api/cronjob/check-storage.test.ts @@ -1,4 +1,4 @@ -import handler from '~/pages/api/cronjob/getStorageUsed'; +import handler from '~/pages/api/cronjob/check-storage'; import { createMocks } from 'node-mocks-http'; import { ConfigService, ShellService } from '~/services'; diff --git a/pages/api/cronjob/getStorageUsed.ts b/pages/api/cronjob/check-storage.ts similarity index 100% rename from pages/api/cronjob/getStorageUsed.ts rename to pages/api/cronjob/check-storage.ts diff --git a/pages/api/account/tokenManager.test.ts b/pages/api/integration/token-manager.test.ts similarity index 98% rename from pages/api/account/tokenManager.test.ts rename to pages/api/integration/token-manager.test.ts index 9728716..cbe0dc8 100644 --- a/pages/api/account/tokenManager.test.ts +++ b/pages/api/integration/token-manager.test.ts @@ -1,4 +1,4 @@ -import handler from '~/pages/api/account/tokenManager'; +import handler from '~/pages/api/integration/token-manager'; import { createMocks } from 'node-mocks-http'; import { getServerSession } from 'next-auth/next'; import { ConfigService } from '~/services'; diff --git a/pages/api/account/tokenManager.ts b/pages/api/integration/token-manager.ts similarity index 100% rename from pages/api/account/tokenManager.ts rename to pages/api/integration/token-manager.ts diff --git a/pages/api/account/updateAppriseAlert.test.ts b/pages/api/notif/apprise/alert.test.ts similarity index 54% rename from pages/api/account/updateAppriseAlert.test.ts rename to pages/api/notif/apprise/alert.test.ts index 2700ffb..5ee3958 100644 --- a/pages/api/account/updateAppriseAlert.test.ts +++ b/pages/api/notif/apprise/alert.test.ts @@ -1,12 +1,101 @@ -import { createMocks } from 'node-mocks-http'; -import handler from '~/pages/api/account/updateAppriseAlert'; import { getServerSession } from 'next-auth/next'; +import { createMocks } from 'node-mocks-http'; import { ConfigService } from '~/services'; +import handler from 'pages/api/notif/apprise/alert'; vi.mock('next-auth/next'); vi.mock('~/services'); -describe('Notifications API', () => { +describe('Get Apprise Alert API', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + + it('should return 405 if the method is not GET', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'Lovelace' }, + }); + 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 () => { + vi.mocked(getServerSession).mockResolvedValue(null); + const { req, res } = createMocks({ method: 'GET' }); + await handler(req, res); + expect(res._getStatusCode()).toBe(401); + }); + + it('should return 400 if the user does not exist', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'nonexistent' }, + }); + + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + 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 () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'testuser' }, + }); + + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + 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 () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'testuser' }, + }); + + vi.mocked(ConfigService.getUsersList).mockImplementation(() => { + throw new Error(); + }); + + const { req, res } = createMocks({ method: 'GET' }); + await handler(req, res); + + expect(res._getStatusCode()).toBe(500); + expect(res._getJSONData()).toEqual({ + status: 500, + message: 'API error, contact the administrator', + }); + }); +}); + +describe('Update Apprise Alert API', () => { beforeEach(() => { vi.clearAllMocks(); vi.resetModules(); @@ -14,8 +103,11 @@ describe('Notifications API', () => { vi.spyOn(console, 'log').mockImplementation(() => {}); }); - it('should return 405 if the method is not PUT', async () => { - const { req, res } = createMocks({ method: 'GET' }); + it('should return 405 if the method is not allowed', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'Lovelace' }, + }); + const { req, res } = createMocks({ method: 'POST' }); await handler(req, res); expect(res._getStatusCode()).toBe(405); }); diff --git a/pages/api/notif/apprise/alert.ts b/pages/api/notif/apprise/alert.ts new file mode 100644 index 0000000..814b46e --- /dev/null +++ b/pages/api/notif/apprise/alert.ts @@ -0,0 +1,75 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { getServerSession } from 'next-auth/next'; +import { ConfigService } from '~/services'; +import { ErrorResponse, AppriseAlertResponse } from '~/types'; +import { authOptions } from '../../auth/[...nextauth]'; +import ApiResponse from '~/helpers/functions/apiResponse'; + +export default async function handler( + req: NextApiRequest & { body: { appriseAlert: boolean } }, + res: NextApiResponse +) { + const session = await getServerSession(req, res, authOptions); + if (!session) { + return ApiResponse.unauthorized(res); + } + + if (req.method == 'GET') { + try { + const usersList = await ConfigService.getUsersList(); + + //Verify that the user of the session exists + const user = usersList.find((u) => u.username === session.user?.name); + if (!user) { + res.status(400).json({ + message: 'User is incorrect. Please, logout to update your session.', + }); + return; + } + + res.status(200).json({ appriseAlert: user.appriseAlert }); + } catch (error: any) { + console.log(error); + const errorMessage = + error.code === 'ENOENT' + ? 'No such file or directory' + : 'API error, contact the administrator'; + + res.status(500).json({ status: 500, message: errorMessage }); + } + } else if (req.method == 'PUT') { + const { appriseAlert } = req.body; + if (typeof appriseAlert !== 'boolean') { + return res.status(422).json({ message: 'Unexpected data' }); + } + + try { + const usersList = await ConfigService.getUsersList(); + const userIndex = usersList.findIndex((u) => u.username === session.user?.name); + + if (userIndex === -1) { + return res + .status(400) + .json({ message: 'User is incorrect. Please, logout to update your session.' }); + } + + const updatedUsersList = usersList.map((user, index) => + index === userIndex ? { ...user, appriseAlert } : user + ); + + await ConfigService.updateUsersList(updatedUsersList); + return res.status(200).json({ message: 'Successful API send' }); + } catch (error: any) { + console.log(error); + return res.status(500).json({ + status: 500, + message: + error.code === 'ENOENT' + ? 'No such file or directory' + : 'API error, contact the administrator', + }); + } + } else { + return ApiResponse.methodNotAllowed(res); + } +} diff --git a/pages/api/account/getAppriseMode.test.ts b/pages/api/notif/apprise/mode.test.ts similarity index 50% rename from pages/api/account/getAppriseMode.test.ts rename to pages/api/notif/apprise/mode.test.ts index 81747f9..31cf691 100644 --- a/pages/api/account/getAppriseMode.test.ts +++ b/pages/api/notif/apprise/mode.test.ts @@ -1,7 +1,7 @@ import { getServerSession } from 'next-auth/next'; import { createMocks } from 'node-mocks-http'; import { ConfigService } from '~/services'; -import handler from '~/pages/api/account/getAppriseMode'; +import handler from '~/pages/api/notif/apprise/mode'; import { AppriseModeEnum } from '~/types/domain/config.types'; vi.mock('next-auth/next'); @@ -14,6 +14,9 @@ describe('Get Apprise Mode API', () => { }); it('should return 405 if the method is not GET', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'Lovelace' }, + }); const { req, res } = createMocks({ method: 'POST' }); await handler(req, res); expect(res._getStatusCode()).toBe(405); @@ -24,7 +27,6 @@ describe('Get Apprise Mode API', () => { 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 () => { @@ -98,3 +100,92 @@ describe('Get Apprise Mode API', () => { }); }); }); + +describe('Apprise Mode Update API', () => { + it('should return 405 if method is not allowed', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'Lovelace' }, + }); + const { req, res } = createMocks({ method: 'POST' }); + await handler(req, res); + expect(res._getStatusCode()).toBe(405); + }); + + it('should return 401 if not authenticated', async () => { + vi.mocked(getServerSession).mockResolvedValue(null); + + const { req, res } = createMocks({ method: 'PUT' }); + await handler(req, res); + + expect(res._getStatusCode()).toBe(401); + }); + + it('should return 422 if invalid data is provided', async () => { + vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testuser' } }); + + const { req, res } = createMocks({ + method: 'PUT', + body: { appriseMode: 'invalid-mode', appriseStatelessURL: 'https://example.com' }, + }); + + await handler(req, res); + expect(res._getStatusCode()).toBe(422); + }); + + it('should return 400 if user does not exist', async () => { + vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'unknownuser' } }); + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + appriseMode: AppriseModeEnum.PACKAGE, + }, + ]); + + const { req, res } = createMocks({ + method: 'PUT', + body: { appriseMode: 'stateless', appriseStatelessURL: 'https://example.com' }, + }); + + await handler(req, res); + expect(res._getStatusCode()).toBe(400); + }); + + it('should update user settings and return 200', async () => { + vi.mocked(getServerSession).mockResolvedValue({ user: { name: 'testuser' } }); + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + appriseMode: AppriseModeEnum.PACKAGE, + }, + ]); + vi.mocked(ConfigService.updateUsersList).mockResolvedValue(); + + const { req, res } = createMocks({ + method: 'PUT', + body: { appriseMode: 'stateless', appriseStatelessURL: 'https://example.com' }, + }); + + await handler(req, res); + + expect(ConfigService.updateUsersList).toHaveBeenCalledWith([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + appriseMode: AppriseModeEnum.STATELESS, + appriseStatelessURL: 'https://example.com', + }, + ]); + expect(res._getStatusCode()).toBe(200); + }); +}); diff --git a/pages/api/notif/apprise/mode.ts b/pages/api/notif/apprise/mode.ts new file mode 100644 index 0000000..00b5f44 --- /dev/null +++ b/pages/api/notif/apprise/mode.ts @@ -0,0 +1,78 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { getServerSession } from 'next-auth/next'; +import { ConfigService } from '~/services'; +import { authOptions } from '../../auth/[...nextauth]'; +import { AppriseModeDTO, ErrorResponse } from '~/types'; +import ApiResponse from '~/helpers/functions/apiResponse'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const session = await getServerSession(req, res, authOptions); + if (!session) { + return ApiResponse.unauthorized(res); + } + + if (req.method == 'GET') { + try { + const usersList = await ConfigService.getUsersList(); + + //Verify that the user of the session exists + const user = usersList.find((u) => u.username === session.user?.name); + if (!user) { + res.status(400).json({ + message: 'User is incorrect. Please, logout to update your session.', + }); + return; + } + res.status(200).json({ + appriseMode: user.appriseMode, + appriseStatelessURL: user.appriseStatelessURL, + }); + } catch (error: any) { + console.log(error); + const errorMessage = + error.code === 'ENOENT' + ? 'No such file or directory' + : 'API error, contact the administrator'; + + res.status(500).json({ status: 500, message: errorMessage }); + } + } else if (req.method == 'PUT') { + const { appriseMode, appriseStatelessURL } = req.body; + + if (!['package', 'stateless'].includes(appriseMode)) { + return res.status(422).json({ message: 'Unexpected data' }); + } + + try { + const usersList = await ConfigService.getUsersList(); + const userIndex = usersList.findIndex((user) => user.username === session.user?.name); + + if (userIndex === -1) { + return res.status(400).json({ + message: 'User is incorrect. Please, logout to update your session.', + }); + } + + const updatedUsersList = usersList.map((user, index) => + index === userIndex ? { ...user, appriseMode, appriseStatelessURL } : user + ); + + await ConfigService.updateUsersList(updatedUsersList); + return res.status(200).json({ message: 'Successful API send' }); + } catch (error: any) { + console.log(error); + return res.status(500).json({ + status: 500, + message: + error.code === 'ENOENT' + ? 'No such file or directory' + : 'API error, contact the administrator', + }); + } + } else { + return ApiResponse.methodNotAllowed(res); + } +} diff --git a/pages/api/account/sendTestApprise.ts b/pages/api/notif/apprise/send-test.ts similarity index 98% rename from pages/api/account/sendTestApprise.ts rename to pages/api/notif/apprise/send-test.ts index b44bc26..0b5d7f7 100644 --- a/pages/api/account/sendTestApprise.ts +++ b/pages/api/notif/apprise/send-test.ts @@ -4,7 +4,7 @@ import { getServerSession } from 'next-auth/next'; import { promisify } from 'util'; import { ConfigService } from '~/services'; import { ErrorResponse, SuccessResponse } from '~/types'; -import { authOptions } from '../auth/[...nextauth]'; +import { authOptions } from '../../auth/[...nextauth]'; const execAsync = promisify(exec); diff --git a/pages/api/account/updateAppriseServices.test.ts b/pages/api/notif/apprise/services.test.ts similarity index 54% rename from pages/api/account/updateAppriseServices.test.ts rename to pages/api/notif/apprise/services.test.ts index d0d7a10..2cbe40b 100644 --- a/pages/api/account/updateAppriseServices.test.ts +++ b/pages/api/notif/apprise/services.test.ts @@ -1,12 +1,104 @@ -import { createMocks } from 'node-mocks-http'; -import handler from '~/pages/api/account/updateAppriseServices'; import { getServerSession } from 'next-auth/next'; +import { createMocks } from 'node-mocks-http'; import { ConfigService } from '~/services'; +import handler from '~/pages/api/notif/apprise/services'; vi.mock('next-auth/next'); vi.mock('~/services'); -describe('PUT /api/account/updateAppriseURLs', () => { +describe('Get Apprise Services API', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + + it('should return 405 if the method is not GET', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'Lovelace' }, + }); + 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 () => { + vi.mocked(getServerSession).mockResolvedValue(null); + const { req, res } = createMocks({ method: 'GET' }); + await handler(req, res); + expect(res._getStatusCode()).toBe(401); + }); + + it('should return 400 if the user does not exist', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'nonexistent' }, + }); + + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + 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 () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'testuser' }, + }); + + vi.mocked(ConfigService.getUsersList).mockResolvedValue([ + { + id: 1, + username: 'testuser', + password: 'hashedpassword', + roles: ['user'], + email: 'testuser@example.com', + 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 () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'testuser' }, + }); + + vi.mocked(ConfigService.getUsersList).mockImplementation(() => { + throw new Error(); + }); + + const { req, res } = createMocks({ method: 'GET' }); + await handler(req, res); + + expect(res._getStatusCode()).toBe(500); + expect(res._getJSONData()).toEqual({ + status: 500, + message: 'API error, contact the administrator', + }); + }); +}); + +describe('PUT Apprise services API', () => { beforeEach(() => { vi.clearAllMocks(); vi.resetModules(); @@ -24,8 +116,11 @@ describe('PUT /api/account/updateAppriseURLs', () => { expect(res._getStatusCode()).toBe(401); }); - it('should return 405 if method is not PUT', async () => { - const { req, res } = createMocks({ method: 'GET' }); + it('should return 405 if method is not handling', async () => { + vi.mocked(getServerSession).mockResolvedValue({ + user: { name: 'Lovelace' }, + }); + const { req, res } = createMocks({ method: 'DELETE' }); await handler(req, res); expect(res._getStatusCode()).toBe(405); diff --git a/pages/api/notif/apprise/services.ts b/pages/api/notif/apprise/services.ts new file mode 100644 index 0000000..c3d78f4 --- /dev/null +++ b/pages/api/notif/apprise/services.ts @@ -0,0 +1,80 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { getServerSession } from 'next-auth/next'; +import { ConfigService } from '~/services'; +import { authOptions } from '../../auth/[...nextauth]'; +import { AppriseServicesDTO, ErrorResponse } from '~/types'; +import ApiResponse from '~/helpers/functions/apiResponse'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const session = await getServerSession(req, res, authOptions); + if (!session) { + return ApiResponse.unauthorized(res); + } + + if (req.method == 'GET') { + try { + const usersList = await ConfigService.getUsersList(); + + //Verify that the user of the session exists + const user = usersList.find((u) => u.username === session.user?.name); + if (!user) { + res.status(400).json({ + message: 'User is incorrect. Please, logout to update your session.', + }); + return; + } + + res.status(200).json({ + appriseServices: user.appriseServices, + }); + } catch (error: any) { + console.log(error); + const errorMessage = + error.code === 'ENOENT' + ? 'No such file or directory' + : 'API error, contact the administrator'; + + res.status(500).json({ status: 500, message: errorMessage }); + } + } else if (req.method == 'PUT') { + const { appriseURLs } = req.body; + + try { + const usersList = await ConfigService.getUsersList(); + const userIndex = usersList.findIndex((user) => user.username === session.user?.name); + + if (userIndex === -1) { + return res.status(400).json({ + message: 'User is incorrect. Please, logout to update your session.', + }); + } + + //Build the services URLs list from form + const appriseURLsArray = appriseURLs + .replace(/ /g, '') + .split('\n') + .filter((el: string) => el != ''); + + const updatedUsersList = usersList.map((user, index) => + index === userIndex ? { ...user, appriseServices: appriseURLsArray } : user + ); + + await ConfigService.updateUsersList(updatedUsersList); + return res.status(200).json({ message: 'Successful API send' }); + } catch (error: any) { + console.log(error); + return res.status(500).json({ + status: 500, + message: + error.code === 'ENOENT' + ? 'No such file or directory' + : 'API error, contact the administrator', + }); + } + } else { + return ApiResponse.methodNotAllowed(res); + } +}