diff --git a/client/src/ui/requests.js b/client/src/ui/requests.js index 3376b9f..a7f24a4 100644 --- a/client/src/ui/requests.js +++ b/client/src/ui/requests.js @@ -194,7 +194,7 @@ function createRequestCard(request) { const actions = document.createElement('span'); actions.className = 'service-icons-container'; - const id = request.theTvDbId || request.theMovieDbId || request.theTvdbId || request.theTmdbId || request.TvDbId || request.TheTvDbId || request.imdbId || request.ImdbId; + const id = request.theTvDbId || request.theTvdbId || request.tvDbId || request.tvdbId || request.TvDbId || request.TheTvDbId || request.theMovieDbId || request.theTmdbId || request.imdbId || request.ImdbId; if (state.ombiBaseUrl && id) { const ombiLink = document.createElement('a'); ombiLink.className = 'ombi-link'; diff --git a/server/utils/ombiHelpers.js b/server/utils/ombiHelpers.js index fecf5b2..86d288b 100644 --- a/server/utils/ombiHelpers.js +++ b/server/utils/ombiHelpers.js @@ -115,10 +115,10 @@ async function decorateRequestsWithArrLinks(requests, isAdmin) { requests.forEach(req => { // Determine if it's TV or Movie. Often `mediaType` is set, or `type === 'Tv'` // Fallback to checking for TV specific IDs. - const isTv = req.mediaType === 'tv' || req.type === 'Tv' || req.tvDbId || req.theTvDbId; + const isTv = req.mediaType === 'tv' || req.type === 'Tv' || req.tvDbId || req.tvdbId || req.theTvDbId || req.theTvdbId || req.TvDbId || req.TheTvDbId; if (isTv) { - const tvdbId = req.theTvDbId || req.theMovieDbId || req.theTvdbId || req.theTmdbId || req.TvDbId || req.TheTvDbId; + const tvdbId = req.theTvDbId || req.theTvdbId || req.tvDbId || req.tvdbId || req.TvDbId || req.TheTvDbId || req.theMovieDbId || req.theTmdbId; if (!tvdbId) return; for (const instData of sonarrData) { diff --git a/tests/integration/ombi.test.js b/tests/integration/ombi.test.js index 27a9198..9f186f0 100644 --- a/tests/integration/ombi.test.js +++ b/tests/integration/ombi.test.js @@ -233,6 +233,48 @@ describe('GET /api/ombi/requests', () => { expect(res.body.requests.movie[0].requestedUser.userName).toBe('adminuser'); }); + it('decorates TV requests with Sonarr links using tvDbId camelCase property (Issue #58)', async () => { + // 1. Setup mock instance config + process.env.SONARR_INSTANCES = JSON.stringify([ + { id: 'sonarr-1', name: 'Test Sonarr', url: 'https://sonarr.test', apiKey: 'sonarr-key' } + ]); + + // Reset and re-initialize retrievers registry to pick up the Sonarr instance + arrRetrieverRegistry.retrievers.clear(); + arrRetrieverRegistry.initialized = false; + + // 2. Setup mock Ombi TV request carrying `tvDbId` instead of `theTvDbId` + const tvRequestsWithTvDbId = [ + { id: 4, title: 'Superman Show', requestedUser: { userName: 'adminuser' }, requestedByAlias: 'adminuser', type: 'tv', tvDbId: '101' } + ]; + + nock.cleanAll(); + setupOmbiRequestMocks(OMBI_REQUESTS.movie, tvRequestsWithTvDbId); + + // 3. Mock Sonarr API series call returning the series with matching tvdbId and titleSlug + nock('https://sonarr.test') + .get('/api/v3/series') + .reply(200, [ + { tvdbId: 101, title: 'Superman Show', titleSlug: 'superman-show' } + ]); + + const { cookies } = await authenticateUser(app, 'AdminUser', true); + + const res = await request(app) + .get('/api/ombi/requests?showAll=true') + .set('Cookie', cookies) + .expect(200); + + // 4. Assert decoration succeeded + const supermanShow = res.body.requests.tv.find(r => r.id === 4); + expect(supermanShow).toBeDefined(); + expect(supermanShow.arrLink).toBe('https://sonarr.test/series/superman-show'); + expect(supermanShow.arrType).toBe('sonarr'); + + // Clean up + delete process.env.SONARR_INSTANCES; + }); + it('handles case-insensitive username matching', async () => { const requestsWithMixedCase = [ { id: 1, title: 'Test Movie', requestedUser: { userName: 'TestUser' }, requestedByAlias: 'TestUser', type: 'movie' },