mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
Admin requests: paginated API & UI overhaul
Add a paginated Admin Requests API and fully refactor the admin requests UI to support filtering, sorting, pagination, and URL state. - New API: src/app/api/admin/requests/route.ts implements paginated, searchable, filterable, and sortable request listing with proper relation includes and pagination metadata. - Frontend: RecentRequestsTable rewritten to fetch via SWR (authenticatedFetcher), read/write URL query params, debounce search, support status/user filters, sortable columns, page size selector, and full pagination UI; added loading/error states and toast feedback for actions. - Admin page updated to use Suspense and the new RecentRequestsTable (component now fetches its own data). - Settings: deprecated single download-client PUT route now maps updates into the new multi-client format (download_clients JSON), logs deprecation, and invalidates download client manager; settings GET now reads multi-client config for backward compatibility. - Processors: monitor-download and retry-failed-imports updated to use the download-client-manager and new PathMappingConfig shape for path mapping logic. - Minor API/schema updates: request-with-torrent schema extended (indexerId, infoUrl, protocol) and setup complete no longer writes legacy path keys. - Tests updated to reflect API and processor changes. This change centralizes request management on the server, modernizes the UI for large datasets, and migrates download client settings toward a multi-client configuration while keeping backward compatibility.
This commit is contained in:
@@ -8,8 +8,9 @@ import { MonitorDownloadPayload, getJobQueueService } from '../services/job-queu
|
||||
import { prisma } from '../db';
|
||||
import { getQBittorrentService } from '../integrations/qbittorrent.service';
|
||||
import { RMABLogger } from '../utils/logger';
|
||||
import { PathMapper } from '../utils/path-mapper';
|
||||
import { PathMapper, PathMappingConfig } from '../utils/path-mapper';
|
||||
import { getConfigService } from '../services/config.service';
|
||||
import { getDownloadClientManager } from '../services/download-client-manager.service';
|
||||
|
||||
/**
|
||||
* Helper function to retry getTorrent with exponential backoff
|
||||
@@ -130,20 +131,23 @@ export async function processMonitorDownload(payload: MonitorDownloadPayload): P
|
||||
throw new Error('Download path not available from download client');
|
||||
}
|
||||
|
||||
// Load path mapping configuration
|
||||
// Get path mapping configuration from the specific download client
|
||||
const configService = getConfigService();
|
||||
const pathMappingConfig = await configService.getMany([
|
||||
'download_client_remote_path_mapping_enabled',
|
||||
'download_client_remote_path',
|
||||
'download_client_local_path',
|
||||
]);
|
||||
const manager = getDownloadClientManager(configService);
|
||||
const protocol = downloadClient === 'sabnzbd' ? 'usenet' : 'torrent';
|
||||
const clientConfig = await manager.getClientForProtocol(protocol);
|
||||
|
||||
// Build path mapping config from client settings
|
||||
const pathMappingConfig: PathMappingConfig = clientConfig && clientConfig.remotePathMappingEnabled
|
||||
? {
|
||||
enabled: true,
|
||||
remotePath: clientConfig.remotePath || '',
|
||||
localPath: clientConfig.localPath || '',
|
||||
}
|
||||
: { enabled: false, remotePath: '', localPath: '' };
|
||||
|
||||
// Apply remote-to-local path transformation if enabled
|
||||
const organizePath = PathMapper.transform(downloadPath, {
|
||||
enabled: pathMappingConfig.download_client_remote_path_mapping_enabled === 'true',
|
||||
remotePath: pathMappingConfig.download_client_remote_path || '',
|
||||
localPath: pathMappingConfig.download_client_local_path || '',
|
||||
});
|
||||
const organizePath = PathMapper.transform(downloadPath, pathMappingConfig);
|
||||
|
||||
logger.info(`Download completed`, {
|
||||
downloadClient,
|
||||
|
||||
@@ -9,7 +9,8 @@ import { prisma } from '../db';
|
||||
import { RMABLogger } from '../utils/logger';
|
||||
import { getJobQueueService } from '../services/job-queue.service';
|
||||
import { getConfigService } from '../services/config.service';
|
||||
import { PathMapper } from '../utils/path-mapper';
|
||||
import { getDownloadClientManager } from '../services/download-client-manager.service';
|
||||
import { PathMapper, PathMappingConfig } from '../utils/path-mapper';
|
||||
|
||||
export interface RetryFailedImportsPayload {
|
||||
jobId?: string;
|
||||
@@ -23,18 +24,23 @@ export async function processRetryFailedImports(payload: RetryFailedImportsPaylo
|
||||
logger.info('Starting retry job for requests awaiting import...');
|
||||
|
||||
try {
|
||||
// Load path mapping configuration once
|
||||
// Initialize config and download client manager
|
||||
const configService = getConfigService();
|
||||
const pathMappingConfig = await configService.getMany([
|
||||
'download_client_remote_path_mapping_enabled',
|
||||
'download_client_remote_path',
|
||||
'download_client_local_path',
|
||||
]);
|
||||
const manager = getDownloadClientManager(configService);
|
||||
|
||||
const mappingConfig = {
|
||||
enabled: pathMappingConfig.download_client_remote_path_mapping_enabled === 'true',
|
||||
remotePath: pathMappingConfig.download_client_remote_path || '',
|
||||
localPath: pathMappingConfig.download_client_local_path || '',
|
||||
// Helper function to get path mapping config for a specific download client type
|
||||
const getPathMappingForClient = async (clientType: string): Promise<PathMappingConfig> => {
|
||||
const protocol = clientType === 'sabnzbd' ? 'usenet' : 'torrent';
|
||||
const clientConfig = await manager.getClientForProtocol(protocol);
|
||||
|
||||
if (clientConfig && clientConfig.remotePathMappingEnabled) {
|
||||
return {
|
||||
enabled: true,
|
||||
remotePath: clientConfig.remotePath || '',
|
||||
localPath: clientConfig.localPath || '',
|
||||
};
|
||||
}
|
||||
return { enabled: false, remotePath: '', localPath: '' };
|
||||
};
|
||||
|
||||
// Find all active requests in awaiting_import status
|
||||
@@ -83,6 +89,10 @@ export async function processRetryFailedImports(payload: RetryFailedImportsPaylo
|
||||
let downloadPath: string;
|
||||
|
||||
// Try to get download path from the appropriate download client
|
||||
// Get path mapping for this specific download client
|
||||
const clientType = downloadHistory.downloadClient || 'qbittorrent';
|
||||
const mappingConfig = await getPathMappingForClient(clientType);
|
||||
|
||||
if (downloadHistory.torrentHash) {
|
||||
// qBittorrent download
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user