diff --git a/backend/app/arr/__init__.py b/backend/app/arr/__init__.py index 30dc1d8..51029e8 100644 --- a/backend/app/arr/__init__.py +++ b/backend/app/arr/__init__.py @@ -46,8 +46,15 @@ def add_config(): try: config = request.json result = save_arr_config(config) + + # Handle the conflict case first + if not result['success'] and result.get('status_code') == 409: + return jsonify({'success': False, 'error': result['error']}), 409 + + # Handle other failure cases if not result['success']: return jsonify(result), 400 + return jsonify(result), 200 except Exception as e: logger.error(f"Error saving arr config: {str(e)}") @@ -88,15 +95,25 @@ def handle_config(id): }), 404 elif request.method == 'PUT': - success = update_arr_config(id, request.json) - if success: - logger.debug(f"Updated arr config: {id}") - return jsonify({'success': True}), 200 - logger.debug(f"Arr config not found for update: {id}") - return jsonify({ - 'success': False, - 'error': 'Config not found' - }), 404 + result = update_arr_config(id, request.json) + + # Handle the conflict case first + if not result['success'] and result.get('status_code') == 409: + return jsonify({ + 'success': False, + 'error': result['error'] + }), 409 + + # Handle other failure cases + if not result['success']: + logger.debug(f"Arr config not found for update: {id}") + return jsonify({ + 'success': False, + 'error': 'Config not found' + }), 404 + + logger.debug(f"Updated arr config: {id}") + return jsonify({'success': True}), 200 elif request.method == 'DELETE': success = delete_arr_config(id) diff --git a/backend/app/arr/manager.py b/backend/app/arr/manager.py index 9e49c43..5453bc2 100644 --- a/backend/app/arr/manager.py +++ b/backend/app/arr/manager.py @@ -23,6 +23,21 @@ def save_arr_config(config): with get_db() as conn: cursor = conn.cursor() try: + # Check if name already exists + existing = cursor.execute( + 'SELECT id FROM arr_config WHERE name = ?', + (config['name'], )).fetchone() + + if existing: + logger.warning( + f"[save_arr_config] Attempted to create duplicate config name: {config['name']}" + ) + return { + 'success': False, + 'error': 'Configuration with this name already exists', + 'status_code': 409 + } + # 1) Insert the arr_config row logger.debug( f"[save_arr_config] Attempting to create new arr_config with name={config['name']} sync_method={config.get('sync_method')}" @@ -94,6 +109,21 @@ def update_arr_config(id, config): with get_db() as conn: cursor = conn.cursor() try: + # Check if name already exists (excluding current config) + existing = cursor.execute( + 'SELECT id FROM arr_config WHERE name = ? AND id != ?', + (config['name'], id)).fetchone() + + if existing: + logger.warning( + f"[update_arr_config] Attempted to update config #{id} to duplicate name: {config['name']}" + ) + return { + 'success': False, + 'error': 'Configuration with this name already exists', + 'status_code': 409 + } + # 1) Grab existing row so we know the existing import_task_id existing_row = cursor.execute( 'SELECT * FROM arr_config WHERE id = ?', (id, )).fetchone() diff --git a/frontend/src/api/arr.js b/frontend/src/api/arr.js index e2f7517..796a4f4 100644 --- a/frontend/src/api/arr.js +++ b/frontend/src/api/arr.js @@ -33,7 +33,18 @@ export const pingService = async (url, apiKey, type) => { export const saveArrConfig = async config => { try { - const response = await axios.post(`/api/arr/config`, config); + const response = await axios.post(`/api/arr/config`, config, { + validateStatus: status => { + return (status >= 200 && status < 300) || status === 409; + } + }); + + if (response.status === 409) { + return { + success: false, + error: 'Configuration with this name already exists' + }; + } return response.data; } catch (error) { console.error('Error saving arr config:', error); @@ -41,24 +52,35 @@ export const saveArrConfig = async config => { } }; +export const updateArrConfig = async (id, config) => { + try { + const response = await axios.put(`/api/arr/config/${id}`, config, { + validateStatus: status => { + return (status >= 200 && status < 300) || status === 409; + } + }); + + if (response.status === 409) { + return { + success: false, + error: 'Configuration with this name already exists' + }; + } + return response.data; + } catch (error) { + console.error('Error updating arr config:', error); + throw error; + } +}; + export const getArrConfigs = async () => { try { const response = await axios.get(`/api/arr/config`); console.log('Raw axios response:', response); console.log('Response data:', response.data); - return response.data; // This is correct - don't change this - } catch (error) { - console.error('Error fetching arr configs:', error); - throw error; - } -}; - -export const updateArrConfig = async (id, config) => { - try { - const response = await axios.put(`/api/arr/config/${id}`, config); return response.data; } catch (error) { - console.error('Error updating arr config:', error); + console.error('Error fetching arr configs:', error); throw error; } }; diff --git a/frontend/src/hooks/useArrModal.js b/frontend/src/hooks/useArrModal.js index cef7a08..4393141 100644 --- a/frontend/src/hooks/useArrModal.js +++ b/frontend/src/hooks/useArrModal.js @@ -211,19 +211,24 @@ export const useArrModal = ({isOpen, onSubmit, editingArr}) => { ? await updateArrConfig(editingArr.id, configToSave) : await saveArrConfig(configToSave); - if (result.success) { - Alert.success( - `Configuration ${ - editingArr ? 'updated' : 'saved' - } successfully` - ); + // Handle the name conflict error specifically + if (!result.success) { + Alert.error(result.error); + setSaveConfirm(false); + return; + } - // If it's not a manual sync method, show the sync confirmation - if (formData.sync_method !== 'manual') { - setShowSyncConfirm(true); - } else { - onSubmit(); - } + Alert.success( + `Configuration ${ + editingArr ? 'updated' : 'saved' + } successfully` + ); + + // If it's not a manual sync method, show the sync confirmation + if (formData.sync_method !== 'manual') { + setShowSyncConfirm(true); + } else { + onSubmit(); } } catch (error) { Alert.error('Failed to save configuration');