Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a021ceba47 | |||
| f8c7e35f31 | |||
| de71580756 | |||
| 2943afdbaf | |||
| 1d571b066d | |||
| db809f2fb3 |
@@ -6,6 +6,22 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||
|
||||
---
|
||||
|
||||
## [1.7.5] - 2026-05-23
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Ombi webhook settings persistence** — Fixed a bug where enabling the Ombi webhook from the frontend was successfully processed by the server but not stored on the Ombi side. The payload submitted to Ombi now retrieves the database `id` of the settings row first and merges it back into the `POST` payload. This ensures Entity Framework Core on the Ombi backend performs an update on the correct database row, enabling the webhook and letting its status persist successfully. Resolves Gitea Issue [#41](https://git.i3omb.com/Gandalf/sofarr/issues/41).
|
||||
|
||||
---
|
||||
|
||||
## [1.7.4] - 2026-05-23
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Ombi webhook registration in production** — Fixed a bug where `/api/ombi/webhook/enable` and other `/api/ombi/*` endpoints returned `404 (Not Found)` in production. The core Express app factory (`server/app.js`) registered the router, but the production server entry point (`server/index.js`) duplicated Express setup instead of utilizing the factory, omitting the `ombiRoutes` registration entirely. Re-registered the router in `server/index.js`, resolves Gitea Issue [#40](https://git.i3omb.com/Gandalf/sofarr/issues/40).
|
||||
|
||||
---
|
||||
|
||||
## [1.7.3] - 2026-05-23
|
||||
|
||||
### Fixed
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sofarr",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sofarr",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sofarr",
|
||||
"version": "1.7.3",
|
||||
"version": "1.7.5",
|
||||
"description": "A personal media download dashboard that shows your downloads 'so far' while you relax on the sofa waiting for your *arr services to finish",
|
||||
"main": "server/index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -89,6 +89,7 @@ const statusRoutes = require('./routes/status');
|
||||
const historyRoutes = require('./routes/history');
|
||||
const authRoutes = require('./routes/auth');
|
||||
const webhookRoutes = require('./routes/webhook');
|
||||
const ombiRoutes = require('./routes/ombi');
|
||||
const verifyCsrf = require('./middleware/verifyCsrf');
|
||||
const { startPoller, POLL_INTERVAL, POLLING_ENABLED } = require('./utils/poller');
|
||||
const { validateInstanceUrl } = require('./utils/config');
|
||||
@@ -372,6 +373,7 @@ app.use('/api/sabnzbd', sabnzbdRoutes);
|
||||
app.use('/api/sonarr', sonarrRoutes);
|
||||
app.use('/api/radarr', radarrRoutes);
|
||||
app.use('/api/emby', embyRoutes);
|
||||
app.use('/api/ombi', ombiRoutes);
|
||||
app.use('/api/dashboard', dashboardRoutes);
|
||||
app.use('/api/status', statusRoutes);
|
||||
app.use('/api/history', historyRoutes);
|
||||
|
||||
@@ -225,9 +225,27 @@ router.post('/webhook/enable', requireAuth, async (req, res) => {
|
||||
|
||||
// Call Ombi API to register webhook
|
||||
const axios = require('axios');
|
||||
|
||||
// Get existing settings to retrieve the database ID
|
||||
const currentRes = await axios.get(
|
||||
`${ombiInst.url}/api/v1/Settings/notifications/webhook`,
|
||||
{
|
||||
headers: {
|
||||
'ApiKey': ombiInst.apiKey
|
||||
}
|
||||
}
|
||||
).catch(err => {
|
||||
logToFile(`[Ombi] Warning fetching existing webhook settings: ${err.message}`);
|
||||
return { data: {} };
|
||||
});
|
||||
|
||||
const currentConfig = currentRes.data || {};
|
||||
const settingsId = currentConfig.id || 0;
|
||||
|
||||
const response = await axios.post(
|
||||
`${ombiInst.url}/api/v1/Settings/notifications/webhook`,
|
||||
{
|
||||
id: settingsId,
|
||||
enabled: true,
|
||||
webhookUrl: webhookUrl,
|
||||
applicationToken: ombiInst.apiKey
|
||||
|
||||
@@ -850,7 +850,15 @@ describe('POST /api/ombi/webhook/enable', () => {
|
||||
|
||||
it('enables webhook successfully', async () => {
|
||||
nock(OMBI_BASE)
|
||||
.post('/api/v1/Settings/notifications/webhook')
|
||||
.get('/api/v1/Settings/notifications/webhook')
|
||||
.reply(200, { id: 42, enabled: false, webhookUrl: null, applicationToken: null });
|
||||
nock(OMBI_BASE)
|
||||
.post('/api/v1/Settings/notifications/webhook', {
|
||||
id: 42,
|
||||
enabled: true,
|
||||
webhookUrl: `${SOFARR_BASE}/api/webhook/ombi`,
|
||||
applicationToken: 'test-ombi-key'
|
||||
})
|
||||
.reply(200, { success: true });
|
||||
|
||||
const { cookies, csrfToken } = await authenticateUser(app, 'TestUser', false);
|
||||
@@ -866,7 +874,34 @@ describe('POST /api/ombi/webhook/enable', () => {
|
||||
expect(res.body.applicationToken).toBe('test-ombi-key');
|
||||
});
|
||||
|
||||
it('enables webhook successfully even if GET settings fails', async () => {
|
||||
nock(OMBI_BASE)
|
||||
.get('/api/v1/Settings/notifications/webhook')
|
||||
.reply(500, { error: 'Failed to fetch settings' });
|
||||
nock(OMBI_BASE)
|
||||
.post('/api/v1/Settings/notifications/webhook', {
|
||||
id: 0,
|
||||
enabled: true,
|
||||
webhookUrl: `${SOFARR_BASE}/api/webhook/ombi`,
|
||||
applicationToken: 'test-ombi-key'
|
||||
})
|
||||
.reply(200, { success: true });
|
||||
|
||||
const { cookies, csrfToken } = await authenticateUser(app, 'TestUser', false);
|
||||
|
||||
const res = await request(app)
|
||||
.post('/api/ombi/webhook/enable')
|
||||
.set('Cookie', cookies)
|
||||
.set('X-CSRF-Token', csrfToken)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.success).toBe(true);
|
||||
});
|
||||
|
||||
it('handles Ombi API errors gracefully', async () => {
|
||||
nock(OMBI_BASE)
|
||||
.get('/api/v1/Settings/notifications/webhook')
|
||||
.reply(200, { id: 42 });
|
||||
nock(OMBI_BASE)
|
||||
.post('/api/v1/Settings/notifications/webhook')
|
||||
.reply(500, { error: 'Internal server error' });
|
||||
|
||||
Reference in New Issue
Block a user