Handle "original" size icon being absent when disabling, falling back on largest size (#22126)

This commit is contained in:
Mathieu Pillard 2024-04-18 17:54:15 +02:00 коммит произвёл GitHub
Родитель ab2da9e475
Коммит 229e8dab84
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 99 добавлений и 3 удалений

Просмотреть файл

@ -0,0 +1,36 @@
from django.core.files.storage import default_storage as storage
from django.core.management.base import BaseCommand
from olympia import amo
from olympia.addons.models import Addon
from olympia.addons.tasks import resize_icon
from olympia.core.logger import getLogger
log = getLogger('z.addons.fix_missing_icons')
class Command(BaseCommand):
help = 'Fix missing icons on specific add-ons'
addon_ids = [271830, 823490, 805933, 583250, 790974, 3006]
def handle(self, *args, **options):
for addon in Addon.objects.filter(pk__in=self.addon_ids):
icon_path = addon.get_icon_path('original')
if storage.exists(icon_path):
log.info(
'Original icon already exists for addon %s, skipping.', addon.pk
)
continue
backup_path = f'static/img/addon-icons/{addon.pk}-64.png'
with open(backup_path, 'rb') as f:
storage.save(storage.path(icon_path), f)
resize_icon.delay(
icon_path,
addon.pk,
amo.ADDON_ICON_SIZES,
set_modified_on=addon.serializable_reference(),
)
log.info(
'Saved new original icon for addon %s and triggered resizing.', addon.pk
)

Просмотреть файл

@ -97,9 +97,13 @@ def delete_all_addon_media_with_backup(id, **kwargs):
disabled_addon_content = DisabledAddonContent.objects.get_or_create(addon=addon)[0]
if addon.icon_type:
base_icon_path = os.path.join(addon.get_icon_dir(), str(addon.pk))
icon_path = f'{base_icon_path}-original.{amo.ADDON_ICON_FORMAT}'
if backup_storage_enabled() and storage.exists(icon_path):
icon_path = None
for size in ['original'] + sorted(amo.ADDON_ICON_SIZES, reverse=True):
_icon_path = addon.get_icon_path(size)
if storage.exists(_icon_path):
icon_path = _icon_path
break
if backup_storage_enabled() and icon_path:
backup_file_name = copy_file_to_backup_storage(icon_path, addon.icon_type)
disabled_addon_content.update(icon_backup_name=backup_file_name)
remove_icons(addon)

Просмотреть файл

@ -1,3 +1,4 @@
import hashlib
import random
from contextlib import contextmanager
from datetime import timedelta
@ -588,3 +589,32 @@ class TestPopulateAccessibilityCategory(TestCase):
assert addon.all_categories == [accessibility_category, shopping_category]
extra_addon.reload()
assert extra_addon.all_categories == [shopping_category]
class TestFixMissingIcons(TestCase):
def test_basic(self):
extra_addons = [addon_factory(), addon_factory()]
addons_with_missing_icons = [
addon_factory(pk=271830),
addon_factory(pk=823490),
addon_factory(pk=805933),
addon_factory(pk=583250),
addon_factory(pk=790974),
addon_factory(pk=3006),
]
call_command('fix_missing_icons')
for addon in extra_addons:
addon.reload()
assert not addon.icon_hash
for size in ['original'] + list(amo.ADDON_ICON_SIZES):
assert not self.root_storage.exists(addon.get_icon_path(size))
for addon in addons_with_missing_icons:
addon.reload()
for size in ['original'] + list(amo.ADDON_ICON_SIZES):
assert self.root_storage.exists(addon.get_icon_path(size))
backup_path = f'{settings.ROOT}/static/img/addon-icons/{addon.pk}-64.png'
with open(backup_path, 'rb') as f:
icon_hash = hashlib.md5(f.read()).hexdigest()[:8]
assert addon.icon_hash == icon_hash

Просмотреть файл

@ -690,6 +690,32 @@ class TestDeleteAndRestoreAllAddonMediaWithFromBackup(TestCase):
DisabledAddonContent.objects.create(addon=self.addon, icon_backup_name='lol')
self.test_delete_all_addon_media_with_backup()
def test_delete_icon_original_does_not_exist(self):
self.addon.update(icon_type='image/png')
# No original icon.
self.root_storage.copy_stored_file(
get_image_path('sunbird-small.png'), self.addon.get_icon_path(128)
)
delete_all_addon_media_with_backup(self.addon.pk)
assert self.copy_file_to_backup_storage_mock.call_count == 1
assert self.copy_file_to_backup_storage_mock.call_args_list[0][0] == (
self.addon.get_icon_path(128),
'image/png',
)
def test_delete_icon_pick_largest_size_that_exists(self):
self.addon.update(icon_type='image/png')
# No original icon, no 128 either.
self.root_storage.copy_stored_file(
get_image_path('sunbird-small.png'), self.addon.get_icon_path(64)
)
delete_all_addon_media_with_backup(self.addon.pk)
assert self.copy_file_to_backup_storage_mock.call_count == 1
assert self.copy_file_to_backup_storage_mock.call_args_list[0][0] == (
self.addon.get_icon_path(64),
'image/png',
)
def test_delete_theme(self):
self.addon.update(type=amo.ADDON_STATICTHEME)
for position in range(1, 3):

Двоичные данные
static/img/addon-icons/271830-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Двоичные данные
static/img/addon-icons/3006-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
static/img/addon-icons/583250-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

Двоичные данные
static/img/addon-icons/790974-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.8 KiB

Двоичные данные
static/img/addon-icons/805933-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.3 KiB

Двоичные данные
static/img/addon-icons/823490-64.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB