mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
Add Transmission/NZBGet and per-client paths and much more
Extend multi-download-client support to include Transmission and NZBGet and introduce per-client custom download paths. Adds protocol mapping and new client types, Transmission/NZBGet integration services, API CRUD and validation changes, UI components/modal updates and live path previews, and manager routing by protocol. Includes DB migrations (download_path on download_history, interactive_search_access on users), schema updates, and related processor/service fixes and tests to ensure backward compatibility and proper path resolution.
This commit is contained in:
@@ -35,6 +35,7 @@ const configServiceMock = vi.hoisted(() => ({
|
||||
}));
|
||||
const downloadClientManagerMock = vi.hoisted(() => ({
|
||||
getAllClients: vi.fn(),
|
||||
testConnection: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/db', () => ({
|
||||
@@ -70,6 +71,13 @@ vi.mock('@/lib/integrations/sabnzbd.service', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/integrations/transmission.service', () => ({
|
||||
TransmissionService: class {
|
||||
constructor() {}
|
||||
testConnection = vi.fn();
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/services/ebook-scraper', () => ({
|
||||
testFlareSolverrConnection: testFlareSolverrMock,
|
||||
}));
|
||||
@@ -189,7 +197,10 @@ describe('Admin settings test routes', () => {
|
||||
});
|
||||
|
||||
it('tests download client connection', async () => {
|
||||
qbtMock.testConnectionWithCredentials.mockResolvedValueOnce('4.0.0');
|
||||
downloadClientManagerMock.testConnection.mockResolvedValueOnce({
|
||||
success: true,
|
||||
message: 'Successfully connected to qbittorrent (v4.0.0)',
|
||||
});
|
||||
const request = {
|
||||
json: vi.fn().mockResolvedValue({ type: 'qbittorrent', url: 'http://qbt', username: 'user', password: 'pass' }),
|
||||
};
|
||||
@@ -199,7 +210,7 @@ describe('Admin settings test routes', () => {
|
||||
const payload = await response.json();
|
||||
|
||||
expect(payload.success).toBe(true);
|
||||
expect(payload.version).toBe('4.0.0');
|
||||
expect(payload.message).toContain('4.0.0');
|
||||
});
|
||||
|
||||
it('validates required fields for download client testing', async () => {
|
||||
@@ -229,7 +240,10 @@ describe('Admin settings test routes', () => {
|
||||
downloadClientManagerMock.getAllClients.mockResolvedValueOnce([
|
||||
{ type: 'qbittorrent', password: 'stored-pass' },
|
||||
]);
|
||||
qbtMock.testConnectionWithCredentials.mockResolvedValueOnce('4.1.0');
|
||||
downloadClientManagerMock.testConnection.mockResolvedValueOnce({
|
||||
success: true,
|
||||
message: 'Successfully connected to qbittorrent (v4.1.0)',
|
||||
});
|
||||
const request = {
|
||||
json: vi.fn().mockResolvedValue({
|
||||
type: 'qbittorrent',
|
||||
@@ -244,12 +258,6 @@ describe('Admin settings test routes', () => {
|
||||
const payload = await response.json();
|
||||
|
||||
expect(payload.success).toBe(true);
|
||||
expect(qbtMock.testConnectionWithCredentials).toHaveBeenCalledWith(
|
||||
'http://qbt',
|
||||
'user',
|
||||
'stored-pass',
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it('returns error when masked password is missing in storage', async () => {
|
||||
@@ -273,7 +281,10 @@ describe('Admin settings test routes', () => {
|
||||
});
|
||||
|
||||
it('returns error when SABnzbd connection fails', async () => {
|
||||
sabnzbdMock.testConnection.mockResolvedValueOnce({ success: false, error: 'bad key' });
|
||||
downloadClientManagerMock.testConnection.mockResolvedValueOnce({
|
||||
success: false,
|
||||
message: 'bad key',
|
||||
});
|
||||
const request = {
|
||||
json: vi.fn().mockResolvedValue({ type: 'sabnzbd', url: 'http://sab', password: 'key' }),
|
||||
};
|
||||
@@ -282,12 +293,15 @@ describe('Admin settings test routes', () => {
|
||||
const response = await POST(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
expect(response.status).toBe(400);
|
||||
expect(payload.error).toMatch(/bad key/);
|
||||
});
|
||||
|
||||
it('requires path mapping values when enabled', async () => {
|
||||
qbtMock.testConnectionWithCredentials.mockResolvedValueOnce('4.0.0');
|
||||
downloadClientManagerMock.testConnection.mockResolvedValueOnce({
|
||||
success: true,
|
||||
message: 'Connected',
|
||||
});
|
||||
const request = {
|
||||
json: vi.fn().mockResolvedValue({
|
||||
type: 'qbittorrent',
|
||||
@@ -307,7 +321,10 @@ describe('Admin settings test routes', () => {
|
||||
});
|
||||
|
||||
it('rejects inaccessible local path when mapping is enabled', async () => {
|
||||
qbtMock.testConnectionWithCredentials.mockResolvedValueOnce('4.0.0');
|
||||
downloadClientManagerMock.testConnection.mockResolvedValueOnce({
|
||||
success: true,
|
||||
message: 'Connected',
|
||||
});
|
||||
fsMock.access.mockRejectedValueOnce(new Error('missing'));
|
||||
const request = {
|
||||
json: vi.fn().mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user