diff --git a/src/olympia/addons/management/commands/process_addons.py b/src/olympia/addons/management/commands/process_addons.py index 3c8c84ebc8..a9159763ec 100644 --- a/src/olympia/addons/management/commands/process_addons.py +++ b/src/olympia/addons/management/commands/process_addons.py @@ -8,6 +8,7 @@ from olympia.addons.models import Addon from olympia.addons.tasks import ( add_dynamic_theme_tag, add_firefox57_tag, bump_appver_for_legacy_addons, delete_addon_not_compatible_with_firefoxes, + disable_legacy_files, delete_obsolete_applicationsversions, find_inconsistencies_between_es_and_db, migrate_legacy_dictionaries_to_webextension, @@ -90,6 +91,14 @@ tasks = { _current_version__files__is_webextension=False), ], }, + 'disable_legacy_files': { + 'method': disable_legacy_files, + 'qs': [ + Q(type__in=(amo.ADDON_EXTENSION, amo.ADDON_THEME, amo.ADDON_LPAPP), + versions__files__is_webextension=False, + versions__files__is_mozilla_signed_extension=False) + ] + }, } diff --git a/src/olympia/addons/tasks.py b/src/olympia/addons/tasks.py index 549006e438..c4ca289bfe 100644 --- a/src/olympia/addons/tasks.py +++ b/src/olympia/addons/tasks.py @@ -31,7 +31,7 @@ from olympia.applications.models import AppVersion from olympia.constants.categories import CATEGORIES from olympia.constants.licenses import ( LICENSE_COPYRIGHT_AR, PERSONA_LICENSES_IDS) -from olympia.files.models import FileUpload +from olympia.files.models import File, FileUpload from olympia.files.utils import RDFExtractor, get_file, parse_addon, SafeZip from olympia.amo.celery import pause_all_tasks, resume_all_tasks from olympia.lib.crypto.packaged import sign_file @@ -747,3 +747,23 @@ def migrate_legacy_dictionary_to_webextension(addon): file_ = version.all_files[0] sign_file(file_) file_.update(datestatuschanged=now, reviewed=now, status=amo.STATUS_PUBLIC) + + +@task +@use_primary_db +def disable_legacy_files(ids, **kw): + """Delete legacy files from the specified add-on ids.""" + log.info( + 'Disabling legacy files from addons %d-%d [%d].', + ids[0], ids[-1], len(ids)) + qs = Addon.unfiltered.filter(id__in=ids) + for addon in qs: + with transaction.atomic(): + # We're dealing with an addon that has the type we care about, and + # that we've identified as containing legacy File instances. + files = File.objects.filter( + is_webextension=False, is_mozilla_signed_extension=False, + version__addon=addon) + for file_ in files: + file_.update(status=amo.STATUS_DISABLED) + index_addons.delay(ids) diff --git a/src/olympia/addons/tests/test_commands.py b/src/olympia/addons/tests/test_commands.py index fd931973c3..a1a682f5f2 100644 --- a/src/olympia/addons/tests/test_commands.py +++ b/src/olympia/addons/tests/test_commands.py @@ -653,3 +653,61 @@ class TestMigrateLegacyDictionariesToWebextension(TestCase): # self.addon2 will raise a ValidationError because of the side_effect # above, so we should only reindex 1 and 3. assert index_addons_mock.call_args[0][0] == [self.addon, self.addon3] + + +class TestDisableLegacyAddons(TestCase): + def test_basic(self): + # These add-ons should be disabled completely since they only have a + # single legacy file. + should_be_fully_disabled = [ + addon_factory(), + addon_factory(type=amo.ADDON_LPAPP), + addon_factory(type=amo.ADDON_THEME), + ] + + # This one has a legacy and a non-legacy version, so only the legacy + # File & Version should be disabled. + should_have_old_version_disabled = [ + addon_factory(created=self.days_ago(42), + version_kw={'created': self.days_ago(42)}), + ] + version_factory( + addon=should_have_old_version_disabled[0], + file_kw={'is_webextension': True}) + + # These should *not* have any File instance disabled, they should be + # kept intact. + should_be_kept_intact = [ + addon_factory(file_kw={'is_webextension': True}), + addon_factory(file_kw={'is_mozilla_signed_extension': True}), + addon_factory(file_kw={'is_mozilla_signed_extension': True, + 'is_webextension': True}), + addon_factory(type=amo.ADDON_DICT), + addon_factory(type=amo.ADDON_SEARCH), + ] + + call_command('process_addons', task='disable_legacy_files') + + for addon in should_be_fully_disabled: + addon.reload() + assert addon.status == amo.STATUS_NULL # No public version left. + assert addon.current_version is None + file_ = addon.versions.all()[0].files.all()[0] + assert file_.status == amo.STATUS_DISABLED + + for addon in should_have_old_version_disabled: + addon.reload() + assert addon.status == amo.STATUS_PUBLIC + assert addon.current_version + file_ = addon.current_version.files.all()[0] + assert file_.status == amo.STATUS_PUBLIC + file_ = addon.versions.exclude( + pk=addon.current_version.pk)[0].files.all()[0] + assert file_.status == amo.STATUS_DISABLED + + for addon in should_be_kept_intact: + addon.reload() + assert addon.status == amo.STATUS_PUBLIC + assert addon.current_version + file_ = addon.versions.all()[0].all_files[0] + assert file_.status == amo.STATUS_PUBLIC