diff --git a/api/ddns_manager.py b/api/ddns_manager.py index f47aba2..8b508bc 100644 --- a/api/ddns_manager.py +++ b/api/ddns_manager.py @@ -386,27 +386,29 @@ class DDNSManager(BaseServiceManager): def register(self, name: str, ip: str) -> dict: """Register the cell's subdomain with the configured provider. - Stores the returned token in the identity config under - identity['domain']['ddns']['token'] and records the subdomain. + Fetches the public IP via ipify when ip is empty. + Stores the returned token in the top-level ddns config (where + update_ip reads it) and updates _identity.domain_name. Returns the dict from provider.register(). """ provider = self.get_provider() if provider is None: raise DDNSError("No DDNS provider configured") + if not ip: + ip = _get_public_ip() or '' + result = provider.register(name, ip) - # Persist token + subdomain back into identity - identity = self._identity() - domain_cfg = dict(identity.get('domain', {})) - ddns_cfg = dict(domain_cfg.get('ddns', {})) - if 'token' in result: - ddns_cfg['token'] = result['token'] - if 'subdomain' in result: - ddns_cfg['subdomain'] = result['subdomain'] - domain_cfg['ddns'] = ddns_cfg if self.config_manager is not None: - self.config_manager.set_identity_field('domain', domain_cfg) + # Token lives in the top-level ddns config so update_ip() can find it + if 'token' in result: + ddns_cfg = dict(self.config_manager.configs.get('ddns', {})) + ddns_cfg['token'] = result['token'] + self.config_manager.set_ddns_config(ddns_cfg) + # Keep domain_name in identity up to date + if 'subdomain' in result: + self.config_manager.set_identity_field('domain_name', result['subdomain']) self._last_ip = ip return result diff --git a/tests/test_ddns_manager.py b/tests/test_ddns_manager.py index 430d14a..43c8d08 100644 --- a/tests/test_ddns_manager.py +++ b/tests/test_ddns_manager.py @@ -307,22 +307,50 @@ class TestUpdateIp(unittest.TestCase): # --------------------------------------------------------------------------- class TestRegister(unittest.TestCase): - def test_register_stores_token_in_config(self): + def test_register_stores_token_in_ddns_config(self): cm = _make_config_manager(ddns_cfg={'provider': 'pic_ngo'}) mgr = DDNSManager(config_manager=cm) mock_provider = MagicMock() - mock_provider.register.return_value = {'token': 'new_tok', 'subdomain': 'alpha'} + mock_provider.register.return_value = {'token': 'new_tok', 'subdomain': 'alpha.pic.ngo'} mgr.get_provider = MagicMock(return_value=mock_provider) result = mgr.register('alpha', '1.2.3.4') self.assertEqual(result['token'], 'new_tok') - # set_identity_field('domain', ...) should have been called - cm.set_identity_field.assert_called_once() - field_name, field_value = cm.set_identity_field.call_args[0] - self.assertEqual(field_name, 'domain') - self.assertEqual(field_value['ddns']['token'], 'new_tok') + # Token saved to top-level ddns config so update_ip() can find it + cm.set_ddns_config.assert_called_once() + saved_ddns = cm.set_ddns_config.call_args[0][0] + self.assertEqual(saved_ddns['token'], 'new_tok') + + # Subdomain saved to _identity.domain_name + cm.set_identity_field.assert_called_once_with('domain_name', 'alpha.pic.ngo') + + def test_register_fetches_public_ip_when_empty(self): + cm = _make_config_manager(ddns_cfg={'provider': 'pic_ngo'}) + mgr = DDNSManager(config_manager=cm) + + mock_provider = MagicMock() + mock_provider.register.return_value = {'token': 't', 'subdomain': 'alpha.pic.ngo'} + mgr.get_provider = MagicMock(return_value=mock_provider) + + with patch('ddns_manager._get_public_ip', return_value='5.6.7.8') as mock_ip: + mgr.register('alpha', '') + mock_ip.assert_called_once() + mock_provider.register.assert_called_once_with('alpha', '5.6.7.8') + + def test_register_uses_provided_ip_without_fetching(self): + cm = _make_config_manager(ddns_cfg={'provider': 'pic_ngo'}) + mgr = DDNSManager(config_manager=cm) + + mock_provider = MagicMock() + mock_provider.register.return_value = {'token': 't', 'subdomain': 'alpha.pic.ngo'} + mgr.get_provider = MagicMock(return_value=mock_provider) + + with patch('ddns_manager._get_public_ip') as mock_ip: + mgr.register('alpha', '1.2.3.4') + mock_ip.assert_not_called() + mock_provider.register.assert_called_once_with('alpha', '1.2.3.4') def test_register_raises_when_no_provider(self): cm = _make_config_manager()