Add Audible region config and user password change modal

Implements configurable Audible region selection in setup and admin settings, affecting all Audible API calls and triggering data refresh on change. Adds a user-facing 'Change Password' modal in the header for local users, moving password change from admin-only to all local users via a new /api/auth/change-password endpoint. Updates documentation, API routes, and context to support these features, and removes the old admin-only password change flow.
This commit is contained in:
kikootwo
2026-01-13 01:51:22 -05:00
parent 50fb5a68af
commit e346f88f42
24 changed files with 932 additions and 317 deletions
@@ -0,0 +1,79 @@
/**
* Component: Audible Settings API
* Documentation: documentation/integrations/audible.md
*/
import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, requireAdmin, AuthenticatedRequest } from '@/lib/middleware/auth';
import { getConfigService } from '@/lib/services/config.service';
import { getAudibleService } from '@/lib/integrations/audible.service';
import { getJobQueueService } from '@/lib/services/job-queue.service';
import { RMABLogger } from '@/lib/utils/logger';
const logger = RMABLogger.create('API.Admin.Settings.Audible');
const VALID_REGIONS = ['us', 'ca', 'uk', 'au', 'in'];
export async function PUT(request: NextRequest) {
return requireAuth(request, async (req: AuthenticatedRequest) => {
return requireAdmin(req, async () => {
try {
const { region } = await request.json();
// Validate region
if (!region || !VALID_REGIONS.includes(region)) {
logger.warn('Invalid region provided', { region });
return NextResponse.json(
{ success: false, error: 'Invalid Audible region. Must be one of: us, ca, uk, au, in' },
{ status: 400 }
);
}
// Save region to configuration
const configService = getConfigService();
await configService.setMany([
{
key: 'audible.region',
value: region,
category: 'system',
description: 'Audible region for metadata and search',
},
]);
// Clear config cache to ensure new region is loaded immediately
configService.clearCache('audible.region');
// Force AudibleService to re-initialize with new region
const audibleService = getAudibleService();
audibleService.forceReinitialize();
logger.info('Audible region updated, triggering data refresh', { region });
// Trigger audible_refresh job to fetch data for new region
try {
const jobQueueService = getJobQueueService();
await jobQueueService.addAudibleRefreshJob();
logger.info('Audible refresh job triggered');
} catch (jobError) {
logger.warn('Failed to trigger audible refresh job', {
error: jobError instanceof Error ? jobError.message : String(jobError),
});
// Don't fail the request if job trigger fails
}
return NextResponse.json({
success: true,
message: `Audible region set to ${region.toUpperCase()}. Data refresh job triggered.`,
});
} catch (error) {
logger.error('Failed to update Audible region', {
error: error instanceof Error ? error.message : String(error),
});
return NextResponse.json(
{ success: false, error: 'Failed to update Audible region settings' },
{ status: 500 }
);
}
});
});
}