token encryption

This commit is contained in:
Rob Walsh
2026-03-03 12:19:12 -07:00
parent 4ae68d01de
commit 8f8387abff
2 changed files with 18 additions and 40 deletions
+15 -35
View File
@@ -189,9 +189,7 @@ export class SchedulerService {
await this.unscheduleJob(job); await this.unscheduleJob(job);
} }
await prisma.scheduledJob.delete({ where: { id: job.id } }); await prisma.scheduledJob.delete({ where: { id: job.id } });
logger.info( logger.info(`Removed deprecated scheduled job: ${job.name} (${job.type})`);
`Removed deprecated scheduled job: ${job.name} (${job.type})`,
);
} }
} catch (error) { } catch (error) {
logger.error('Failed to cleanup deprecated scheduled jobs', { logger.error('Failed to cleanup deprecated scheduled jobs', {
@@ -224,13 +222,11 @@ export class SchedulerService {
job.type, job.type,
{ scheduledJobId: job.id }, { scheduledJobId: job.id },
job.schedule, job.schedule,
`scheduled-${job.id}`, `scheduled-${job.id}`
); );
logger.info(`Job scheduled: ${job.name} (${job.schedule})`); logger.info(`Job scheduled: ${job.name} (${job.schedule})`);
} catch (error) { } catch (error) {
logger.error(`Failed to schedule job ${job.name}`, { logger.error(`Failed to schedule job ${job.name}`, { error: error instanceof Error ? error.message : String(error) });
error: error instanceof Error ? error.message : String(error),
});
throw error; throw error;
} }
} }
@@ -243,13 +239,11 @@ export class SchedulerService {
await this.jobQueue.removeRepeatableJob( await this.jobQueue.removeRepeatableJob(
job.type, job.type,
job.schedule, job.schedule,
`scheduled-${job.id}`, `scheduled-${job.id}`
); );
logger.info(`Job unscheduled: ${job.name}`); logger.info(`Job unscheduled: ${job.name}`);
} catch (error) { } catch (error) {
logger.error(`Failed to unschedule job ${job.name}`, { logger.error(`Failed to unschedule job ${job.name}`, { error: error instanceof Error ? error.message : String(error) });
error: error instanceof Error ? error.message : String(error),
});
// Don't throw - job might not exist in Bull yet // Don't throw - job might not exist in Bull yet
} }
} }
@@ -301,7 +295,7 @@ export class SchedulerService {
*/ */
async updateScheduledJob( async updateScheduledJob(
id: string, id: string,
dto: UpdateScheduledJobDto, dto: UpdateScheduledJobDto
): Promise<ScheduledJob> { ): Promise<ScheduledJob> {
if (dto.schedule) { if (dto.schedule) {
this.validateCronExpression(dto.schedule); this.validateCronExpression(dto.schedule);
@@ -445,8 +439,7 @@ export class SchedulerService {
throw new Error(errorMsg); throw new Error(errorMsg);
} }
libraryId = libraryId = job.payload?.libraryId || absConfig['audiobookshelf.library_id'];
job.payload?.libraryId || absConfig['audiobookshelf.library_id'];
} else { } else {
const plexConfig = await configService.getMany([ const plexConfig = await configService.getMany([
'plex_url', 'plex_url',
@@ -470,18 +463,15 @@ export class SchedulerService {
throw new Error(errorMsg); throw new Error(errorMsg);
} }
libraryId = libraryId = job.payload?.libraryId || plexConfig.plex_audiobook_library_id;
job.payload?.libraryId || plexConfig.plex_audiobook_library_id;
} }
logger.info( logger.info(`Triggering ${backendMode} library scan for library: ${libraryId}`);
`Triggering ${backendMode} library scan for library: ${libraryId}`,
);
return await this.jobQueue.addPlexScanJob( return await this.jobQueue.addPlexScanJob(
libraryId || '', libraryId || '',
job.payload?.partial, job.payload?.partial,
job.payload?.path, job.payload?.path
); );
} }
@@ -502,6 +492,7 @@ export class SchedulerService {
return await this.jobQueue.addAudibleRefreshJob(job.id); return await this.jobQueue.addAudibleRefreshJob(job.id);
} }
/** /**
* Enable a scheduled job * Enable a scheduled job
*/ */
@@ -533,12 +524,10 @@ export class SchedulerService {
await this.triggerJobNow(job.id); await this.triggerJobNow(job.id);
// Stagger triggers to avoid connection pool burst on startup // Stagger triggers to avoid connection pool burst on startup
await new Promise((resolve) => setTimeout(resolve, 500)); await new Promise(resolve => setTimeout(resolve, 500));
} }
} catch (error) { } catch (error) {
logger.error(`Failed to trigger overdue job "${job.name}"`, { logger.error(`Failed to trigger overdue job "${job.name}"`, { error: error instanceof Error ? error.message : String(error) });
error: error instanceof Error ? error.message : String(error),
});
} }
} }
} }
@@ -611,22 +600,13 @@ export class SchedulerService {
if (dayOfMonth === '*' && month === '*' && dayOfWeek === '*') { if (dayOfMonth === '*' && month === '*' && dayOfWeek === '*') {
const hourNum = parseInt(hour, 10); const hourNum = parseInt(hour, 10);
const minuteNum = parseInt(minute, 10); const minuteNum = parseInt(minute, 10);
if ( if (!isNaN(hourNum) && !isNaN(minuteNum) && hourNum >= 0 && hourNum <= 23 && minuteNum >= 0 && minuteNum <= 59) {
!isNaN(hourNum) &&
!isNaN(minuteNum) &&
hourNum >= 0 &&
hourNum <= 23 &&
minuteNum >= 0 &&
minuteNum <= 59
) {
return 24 * 60 * 60 * 1000; // 24 hours return 24 * 60 * 60 * 1000; // 24 hours
} }
} }
// For other patterns, return a conservative default (24 hours) // For other patterns, return a conservative default (24 hours)
logger.warn( logger.warn(`Unknown cron pattern "${cronExpression}", defaulting to 24 hours`);
`Unknown cron pattern "${cronExpression}", defaulting to 24 hours`,
);
return 24 * 60 * 60 * 1000; return 24 * 60 * 60 * 1000;
} }
+3 -5
View File
@@ -77,8 +77,7 @@ describe('SchedulerService', () => {
]) ])
.mockResolvedValue([]); // triggerOverdueJobs .mockResolvedValue([]); // triggerOverdueJobs
const { SchedulerService } = const { SchedulerService } = await import('@/lib/services/scheduler.service');
await import('@/lib/services/scheduler.service');
const service = new SchedulerService(); const service = new SchedulerService();
await service.start(); await service.start();
@@ -87,7 +86,7 @@ describe('SchedulerService', () => {
'audible_refresh', 'audible_refresh',
{ scheduledJobId: 'job-1' }, { scheduledJobId: 'job-1' },
'0 0 * * *', '0 0 * * *',
'scheduled-job-1', 'scheduled-job-1'
); );
}); });
@@ -306,8 +305,7 @@ describe('SchedulerService', () => {
(jobQueueMock as any)[queueMethod].mockResolvedValue('bull-type'); (jobQueueMock as any)[queueMethod].mockResolvedValue('bull-type');
prismaMock.scheduledJob.update.mockResolvedValue({}); prismaMock.scheduledJob.update.mockResolvedValue({});
const { SchedulerService } = const { SchedulerService } = await import('@/lib/services/scheduler.service');
await import('@/lib/services/scheduler.service');
const service = new SchedulerService(); const service = new SchedulerService();
const jobId = await service.triggerJobNow('job-type'); const jobId = await service.triggerJobNow('job-type');