From f75819149512c9c523bdb8ee752e57d0ee9ed39e Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 7 Oct 2026 13:32:55 -0600 Subject: [PATCH] archive: importing domains.yaml keeps domains which have archives Archives create their domain (e.g. one uploaded, or found by a refresh, while WROLPi starts, before domains.yaml is imported). The import deleted every domain missing from the config, and the database deleted that domain's Archives with it. A domain with Archives is now kept (and saved to the config with the next change). Co-Authored-By: Claude Opus 5.5 --- modules/archive/lib.py | 15 +++++--- .../collections/test/test_domains_config.py | 35 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/modules/archive/lib.py b/modules/archive/lib.py index 0b5af39a..e5562577 100644 --- a/modules/archive/lib.py +++ b/modules/archive/lib.py @@ -153,12 +153,19 @@ class DomainsConfig(ConfigFile): collections = Collection.batch_from_config(session, valid_data_list) imported_domains = {c.name for c in collections} - # Delete domain collections that are no longer in config + # Delete domain collections that are no longer in config. A domain with Archives is kept: Archives + # create their domain (e.g. one downloaded before this import), and deleting it would delete them. + with_archives = {i for i, in session.query(Archive.collection_id).distinct()} all_domain_collections = session.query(Collection).filter_by(kind='domain').all() for collection in all_domain_collections: - if collection.name not in imported_domains: - logger.info(f'Deleting domain collection {repr(collection.name)} (no longer in config)') - session.delete(collection) + if collection.name in imported_domains: + continue + if collection.id in with_archives: + logger.warning(f'Keeping domain collection {repr(collection.name)} which is not in config,' + f' because it has archives') + continue + logger.info(f'Deleting domain collection {repr(collection.name)} (no longer in config)') + session.delete(collection) logger.info(f'Successfully imported {len(imported_domains)} domain collections from {file_str}') self.successful_import = True diff --git a/wrolpi/collections/test/test_domains_config.py b/wrolpi/collections/test/test_domains_config.py index 398f04f0..ee1abbc3 100644 --- a/wrolpi/collections/test/test_domains_config.py +++ b/wrolpi/collections/test/test_domains_config.py @@ -296,3 +296,38 @@ async def test_domain_changes_wait_for_config_import(test_session: Session, test domains_config.import_config() request, response = await async_client.put(f'/api/collections/{did}', content=json.dumps(dict(description='x'))) assert response.status_code == HTTPStatus.OK, response.json + + +@pytest.mark.asyncio +async def test_import_keeps_domains_with_archives(test_session: Session, test_directory: pathlib.Path, async_client, + archive_factory): + """A domain missing from domains.yaml is deleted by the import, unless it has Archives. Archives create their + domain (e.g. an upload or refresh while WROLPi starts, before domains.yaml is imported), and deleting it would + delete its Archives.""" + from modules.archive.models import Archive + archive_factory(domain='kept.com', url='https://kept.com/1') + Collection.from_config(test_session, {'name': 'empty.com', 'kind': 'domain'}) + test_session.commit() + domains_config.dump_config() + domains_config.successful_import = False + + # Created before the import. + archive_factory(domain='new.com', url='https://new.com/1') + Collection.from_config(test_session, {'name': 'unused.com', 'kind': 'domain'}) + test_session.commit() + assert test_session.query(Archive).count() == 2 + + domains_config.import_config() + test_session.expire_all() + assert {i.name for i in test_session.query(Collection)} == {'kept.com', 'empty.com', 'new.com'} + assert {i.collection.name for i in test_session.query(Archive)} == {'kept.com', 'new.com'} + assert domains_config.successful_import + + # A domain with Archives which was removed from the config (by hand) is kept too. + config = yaml.safe_load(domains_config.get_file().read_text()) + config['collections'] = [i for i in config['collections'] if i['name'] != 'kept.com'] + domains_config.get_file().write_text(yaml.dump(config)) + domains_config.import_config() + test_session.expire_all() + assert {i.name for i in test_session.query(Collection)} == {'kept.com', 'empty.com', 'new.com'} + assert test_session.query(Archive).count() == 2