def test_extract_theme_properties(zip_file): versions = { amo.DEFAULT_WEBEXT_MAX_VERSION, amo.DEFAULT_STATIC_THEME_MIN_VERSION_FIREFOX, amo.DEFAULT_STATIC_THEME_MIN_VERSION_ANDROID, } for version in versions: AppVersion.objects.create(application=amo.FIREFOX.id, version=version) AppVersion.objects.create(application=amo.ANDROID.id, version=version) addon = addon_factory(type=amo.ADDON_STATICTHEME) result = utils.extract_theme_properties( addon, addon.current_version.channel) assert result == {} # There's no file, but it be should safely handled. # Add the zip in the right place zip_file = os.path.join(settings.ROOT, zip_file) copy_stored_file(zip_file, addon.current_version.all_files[0].file_path) result = utils.extract_theme_properties( addon, addon.current_version.channel) assert result == { "colors": { "frame": "#adb09f", "tab_background_text": "#000" }, "images": { "theme_frame": "weta.png" } }
def from_upload(cls, upload, version, platform, is_beta=False, parsed_data=None): if parsed_data is None: parsed_data = {} addon = version.addon file_ = cls(version=version, platform=platform) upload.path = force_bytes(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] file_.no_restart = parsed_data.get('no_restart', False) file_.strict_compatibility = parsed_data.get('strict_compatibility', False) file_.is_multi_package = parsed_data.get('is_multi_package', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) if (is_beta and addon.status == amo.STATUS_PUBLIC and version.channel == amo.RELEASE_CHANNEL_LISTED): file_.status = amo.STATUS_BETA file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file( upload.path, os.path.join(version.path_prefix, nfd_str(file_.filename))) if upload.validation: # Import loop. from olympia.devhub.tasks import annotate_validation_results from olympia.devhub.utils import ValidationAnnotator validation = annotate_validation_results(validation) FileValidation.from_json(file_, validation) # Copy annotations from any previously approved file. ValidationAnnotator(file_).update_annotations() return file_
def from_upload(cls, upload, version, parsed_data=None): """ Create a File instance from a FileUpload, a Version and the parsed_data generated by parse_addon(). Note that it's the caller's responsability to ensure the file is valid. We can't check for that here because an admin may have overridden the validation results.""" assert parsed_data is not None file_ = cls(version=version) upload_path = force_str(nfd_str(upload.path)) ext = force_str(os.path.splitext(upload_path)[1]) file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload_path) file_.is_restart_required = parsed_data.get('is_restart_required', False) file_.strict_compatibility = parsed_data.get('strict_compatibility', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) file_.is_mozilla_signed_extension = parsed_data.get( 'is_mozilla_signed_extension', False ) file_.hash = file_.generate_hash(upload_path) file_.original_hash = file_.hash file_.manifest_version = parsed_data.get( 'manifest_version', DEFAULT_MANIFEST_VERSION ) file_.save() if file_.is_webextension: permissions = list(parsed_data.get('permissions', [])) optional_permissions = list(parsed_data.get('optional_permissions', [])) # devtools_page isn't in permissions block but treated as one # if a custom devtools page is added by an addon if 'devtools_page' in parsed_data: permissions.append('devtools') # Add content_scripts host matches too. for script in parsed_data.get('content_scripts', []): permissions.extend(script.get('matches', [])) if permissions or optional_permissions: WebextPermission.objects.create( permissions=permissions, optional_permissions=optional_permissions, file=file_, ) log.info(f'New file: {file_!r} from {upload!r}') # Move the uploaded file from the temp location. copy_stored_file(upload_path, file_.current_file_path) if upload.validation: validation = json.loads(upload.validation) FileValidation.from_json(file_, validation) return file_
def test_extract_theme_properties(zip_file): versions = { amo.DEFAULT_WEBEXT_MAX_VERSION, amo.DEFAULT_STATIC_THEME_MIN_VERSION_FIREFOX, amo.DEFAULT_STATIC_THEME_MIN_VERSION_ANDROID, } for version in versions: AppVersion.objects.create(application=amo.FIREFOX.id, version=version) AppVersion.objects.create(application=amo.ANDROID.id, version=version) addon = addon_factory(type=amo.ADDON_STATICTHEME) result = utils.extract_theme_properties(addon, addon.current_version.channel) assert result == {} # There's no file, but it be should safely handled. # Add the zip in the right place zip_file = os.path.join(settings.ROOT, zip_file) copy_stored_file(zip_file, addon.current_version.all_files[0].file_path) result = utils.extract_theme_properties(addon, addon.current_version.channel) assert result == { "colors": { "frame": "#adb09f", "tab_background_text": "#000" }, "images": { "theme_frame": "weta.png" } }
def _mock_xpi_side_effect(self, lwt, upload_path): xpi_path = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/mozilla_static_theme.zip') copy_stored_file(xpi_path, upload_path) assert not os.path.isdir(upload_path) return mock.DEFAULT
def test_recreate_theme_previews(): xpi_path = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/mozilla_static_theme.zip' ) addon_without_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file(xpi_path, addon_without_previews.current_version.file.file_path) addon_with_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file(xpi_path, addon_with_previews.current_version.file.file_path) VersionPreview.objects.create( version=addon_with_previews.current_version, sizes={'image': [123, 456], 'thumbnail': [34, 45]}, ) assert addon_without_previews.current_previews.count() == 0 assert addon_with_previews.current_previews.count() == 1 recreate_theme_previews([addon_without_previews.id, addon_with_previews.id]) assert addon_without_previews.reload().current_previews.count() == 2 assert addon_with_previews.reload().current_previews.count() == 2 sizes = addon_without_previews.current_previews.values_list('sizes', flat=True) renderings = amo.THEME_PREVIEW_RENDERINGS assert list(sizes) == [ { 'image': list(renderings['firefox']['full']), 'thumbnail': list(renderings['firefox']['thumbnail']), 'image_format': renderings['firefox']['image_format'], 'thumbnail_format': renderings['firefox']['thumbnail_format'], }, { 'image': list(renderings['amo']['full']), 'thumbnail': list(renderings['amo']['thumbnail']), 'image_format': renderings['amo']['image_format'], 'thumbnail_format': renderings['amo']['thumbnail_format'], }, ]
def test_can_not_delete_without_discovery_edit_permission(self): uploaded_photo = get_uploaded_file('transparent.png') item = PrimaryHeroImage.objects.create(custom_image=uploaded_photo) src = os.path.join( settings.MEDIA_ROOT, 'hero-featured-image', 'transparent.png') dest = os.path.join( settings.MEDIA_ROOT, 'hero-featured-image', 'thumbs', 'transparent.png') copy_stored_file(src, dest) delete_url = reverse( 'admin:discovery_primaryheroimageupload_delete', args=(item.pk,) ) user = user_factory() self.grant_permission(user, 'Admin:Tools') self.client.login(email=user.email) # Can not access delete confirmation page. response = self.client.get(delete_url, follow=True) assert response.status_code == 403 assert PrimaryHeroImage.objects.filter(pk=item.pk).exists() assert os.path.exists(os.path.join( settings.MEDIA_ROOT, 'hero-featured-image', 'transparent.png')) assert os.path.exists(os.path.join( settings.MEDIA_ROOT, 'hero-featured-image', 'thumbs', 'transparent.png')) # Can not actually delete either. response = self.client.post( delete_url, data={'post': 'yes'}, follow=True) assert response.status_code == 403 assert PrimaryHeroImage.objects.filter(pk=item.pk).exists() assert os.path.exists(os.path.join( settings.MEDIA_ROOT, 'hero-featured-image', 'transparent.png')) assert os.path.exists(os.path.join( settings.MEDIA_ROOT, 'hero-featured-image', 'thumbs', 'transparent.png'))
def test_recreate_theme_previews(): xpi_path = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/mozilla_static_theme.zip') addon_without_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file( xpi_path, addon_without_previews.current_version.all_files[0].file_path) addon_with_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file( xpi_path, addon_with_previews.current_version.all_files[0].file_path) VersionPreview.objects.create( version=addon_with_previews.current_version, sizes={'image': [123, 456], 'thumbnail': [34, 45]}) assert addon_without_previews.current_previews.count() == 0 assert addon_with_previews.current_previews.count() == 1 recreate_theme_previews( [addon_without_previews.id, addon_with_previews.id]) assert addon_without_previews.reload().current_previews.count() == 3 assert addon_with_previews.reload().current_previews.count() == 3 sizes = addon_without_previews.current_previews.values_list( 'sizes', flat=True) assert list(sizes) == [ {'image': list(amo.THEME_PREVIEW_SIZES['header']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['header']['thumbnail'])}, {'image': list(amo.THEME_PREVIEW_SIZES['list']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['list']['thumbnail'])}, {'image': list(amo.THEME_PREVIEW_SIZES['single']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['single']['thumbnail'])}]
def approve_rereview(theme): """Replace original theme with pending theme on filesystem.""" # If reuploaded theme, replace old theme design. storage = LocalFileStorage() rereview = theme.rereviewqueuetheme_set.all() reupload = rereview[0] if reupload.header_path != reupload.theme.header_path: create_persona_preview_images( src=reupload.header_path, full_dst=[ reupload.theme.thumb_path, reupload.theme.icon_path], set_modified_on=reupload.theme.addon.serializable_reference()) if not reupload.theme.is_new(): # Legacy themes also need a preview_large.jpg. # Modern themes use preview.png for both thumb and preview so there # is no problem there. copy_stored_file(reupload.theme.thumb_path, reupload.theme.preview_path, storage=storage) move_stored_file( reupload.header_path, reupload.theme.header_path, storage=storage) theme = reupload.theme rereview.delete() theme_checksum(theme) theme.addon.increment_theme_version_number()
def approve_rereview(theme): """Replace original theme with pending theme on filesystem.""" # If reuploaded theme, replace old theme design. storage = LocalFileStorage() rereview = theme.rereviewqueuetheme_set.all() reupload = rereview[0] if reupload.header_path != reupload.theme.header_path: create_persona_preview_images( src=reupload.header_path, full_dst=[reupload.theme.thumb_path, reupload.theme.icon_path], set_modified_on=reupload.theme.addon.serializable_reference()) if not reupload.theme.is_new(): # Legacy themes also need a preview_large.jpg. # Modern themes use preview.png for both thumb and preview so there # is no problem there. copy_stored_file(reupload.theme.thumb_path, reupload.theme.preview_path, storage=storage) move_stored_file(reupload.header_path, reupload.theme.header_path, storage=storage) theme = reupload.theme rereview.delete() theme_checksum(theme) theme.addon.increment_theme_version_number()
def _mock_xpi_side_effect(self, lwt, upload_path): xpi_path = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/mozilla_static_theme.zip') copy_stored_file(xpi_path, upload_path) assert not os.path.isdir(upload_path) return mock.DEFAULT
def create_custom_icon_from_predefined(addon_ids, **kwargs): addons = Addon.objects.filter(id__in=addon_ids).no_transforms() hashes = {} predefined = os.path.join(settings.ROOT, 'static', 'img', 'addon-icons') _, icons = storage.listdir(predefined) for icon in icons: if b'32' in icon and b'default' not in icon: icon_name = force_str(icon.split(b'-')[0]) with open(os.path.join(predefined, force_str(icon)), 'rb') as fd: hashes[icon_name] = hashlib.md5(fd.read()).hexdigest()[:8] for addon in addons: type_split = addon.icon_type.split('/') if addon.icon_type else [] if len(type_split) != 2 or type_split[0] != 'icon': continue icon_name = type_split[1] destination = addon.get_icon_dir() for size in (32, 64, 128): src = os.path.join(predefined, f'{icon_name}-{size}.png') if not os.path.exists(src): break copy_stored_file( src, os.path.join(destination, f'{addon.id}-{size}.png'), ) else: addon.update(icon_type='image/png', icon_hash=hashes.get(icon_name, ''))
def test_recreate_theme_previews(): xpi_path = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/mozilla_static_theme.zip') addon_without_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file( xpi_path, addon_without_previews.current_version.all_files[0].file_path) addon_with_previews = addon_factory(type=amo.ADDON_STATICTHEME) copy_stored_file( xpi_path, addon_with_previews.current_version.all_files[0].file_path) VersionPreview.objects.create( version=addon_with_previews.current_version, sizes={'image': [123, 456], 'thumbnail': [34, 45]}) assert addon_without_previews.current_previews.count() == 0 assert addon_with_previews.current_previews.count() == 1 recreate_theme_previews( [addon_without_previews.id, addon_with_previews.id]) assert addon_without_previews.reload().current_previews.count() == 3 assert addon_with_previews.reload().current_previews.count() == 3 sizes = addon_without_previews.current_previews.values_list( 'sizes', flat=True) assert list(sizes) == [ {'image': list(amo.THEME_PREVIEW_SIZES['header']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['header']['thumbnail'])}, {'image': list(amo.THEME_PREVIEW_SIZES['list']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['list']['thumbnail'])}, {'image': list(amo.THEME_PREVIEW_SIZES['single']['full']), 'thumbnail': list(amo.THEME_PREVIEW_SIZES['single']['thumbnail'])}]
def from_upload(cls, upload, version, platform, is_beta=False, parsed_data=None): if parsed_data is None: parsed_data = {} addon = version.addon file_ = cls(version=version, platform=platform) upload.path = force_bytes(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] file_.no_restart = parsed_data.get('no_restart', False) file_.strict_compatibility = parsed_data.get('strict_compatibility', False) file_.is_multi_package = parsed_data.get('is_multi_package', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) if (is_beta and addon.status == amo.STATUS_PUBLIC and version.channel == amo.RELEASE_CHANNEL_LISTED): file_.status = amo.STATUS_BETA file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() if file_.is_webextension: permissions = list(parsed_data.get('permissions', [])) # Add content_scripts host matches too. for script in parsed_data.get('content_scripts', []): permissions.extend(script.get('matches', [])) if permissions: WebextPermission.objects.create(permissions=permissions, file=file_) log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file( upload.path, os.path.join(version.path_prefix, nfd_str(file_.filename))) if upload.validation: FileValidation.from_json(file_, validation) return file_
def from_upload(cls, upload, version, platform, parsed_data=None): """ Create a File instance from a FileUpload, a Version, a platform id and the parsed_data generated by parse_addon(). Note that it's the caller's responsability to ensure the file is valid. We can't check for that here because an admin may have overridden the validation results.""" assert parsed_data is not None file_ = cls(version=version, platform=platform) upload.path = force_bytes(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] file_.is_restart_required = parsed_data.get( 'is_restart_required', False) file_.strict_compatibility = parsed_data.get( 'strict_compatibility', False) file_.is_multi_package = parsed_data.get('is_multi_package', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) file_.is_mozilla_signed_extension = parsed_data.get( 'is_mozilla_signed_extension', False) file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() if file_.is_webextension: permissions = list(parsed_data.get('permissions', [])) # Add content_scripts host matches too. for script in parsed_data.get('content_scripts', []): permissions.extend(script.get('matches', [])) if permissions: WebextPermission.objects.create(permissions=permissions, file=file_) log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file( upload.path, os.path.join(version.path_prefix, nfd_str(file_.filename))) if upload.validation: FileValidation.from_json(file_, validation) return file_
def from_upload(cls, upload, version, platform, parsed_data=None): """ Create a File instance from a FileUpload, a Version, a platform id and the parsed_data generated by parse_addon(). Note that it's the caller's responsability to ensure the file is valid. We can't check for that here because an admin may have overridden the validation results.""" assert parsed_data is not None file_ = cls(version=version, platform=platform) upload.path = force_bytes(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] file_.is_restart_required = parsed_data.get('is_restart_required', False) file_.strict_compatibility = parsed_data.get('strict_compatibility', False) file_.is_multi_package = parsed_data.get('is_multi_package', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) file_.is_mozilla_signed_extension = parsed_data.get( 'is_mozilla_signed_extension', False) file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() if file_.is_webextension: permissions = list(parsed_data.get('permissions', [])) # Add content_scripts host matches too. for script in parsed_data.get('content_scripts', []): permissions.extend(script.get('matches', [])) if permissions: WebextPermission.objects.create(permissions=permissions, file=file_) log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file( upload.path, os.path.join(version.path_prefix, nfd_str(file_.filename))) if upload.validation: FileValidation.from_json(file_, validation) return file_
def from_upload(cls, upload, version, platform, is_beta=False, parsed_data=None): if parsed_data is None: parsed_data = {} addon = version.addon file_ = cls(version=version, platform=platform) upload.path = force_bytes(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] file_.is_restart_required = parsed_data.get( 'is_restart_required', False) file_.strict_compatibility = parsed_data.get( 'strict_compatibility', False) file_.is_multi_package = parsed_data.get('is_multi_package', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) file_.is_mozilla_signed_extension = parsed_data.get( 'is_mozilla_signed_extension', False) if (is_beta and addon.status == amo.STATUS_PUBLIC and version.channel == amo.RELEASE_CHANNEL_LISTED): file_.status = amo.STATUS_BETA file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() if file_.is_webextension: permissions = list(parsed_data.get('permissions', [])) # Add content_scripts host matches too. for script in parsed_data.get('content_scripts', []): permissions.extend(script.get('matches', [])) if permissions: WebextPermission.objects.create(permissions=permissions, file=file_) log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file( upload.path, os.path.join(version.path_prefix, nfd_str(file_.filename))) if upload.validation: FileValidation.from_json(file_, validation) return file_
def from_upload(cls, upload, version, platform, is_beta=False, parse_data={}): addon = version.addon file_ = cls(version=version, platform=platform) upload.path = smart_path(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] if file_.jetpack_version: Tag(tag_text='jetpack').save_tag(addon) file_.no_restart = parse_data.get('no_restart', False) file_.strict_compatibility = parse_data.get('strict_compatibility', False) file_.is_multi_package = parse_data.get('is_multi_package', False) file_.is_experiment = parse_data.get('is_experiment', False) file_.is_webextension = parse_data.get('is_webextension', False) if is_beta and addon.status == amo.STATUS_PUBLIC: file_.status = amo.STATUS_BETA file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. destinations = [version.path_prefix] if file_.status in amo.MIRROR_STATUSES: destinations.append(version.mirror_path_prefix) for dest in destinations: copy_stored_file(upload.path, os.path.join(dest, nfd_str(file_.filename))) if upload.validation: # Import loop. from olympia.devhub.tasks import annotate_validation_results from olympia.devhub.utils import ValidationAnnotator validation = annotate_validation_results(validation) FileValidation.from_json(file_, validation) # Copy annotations from any previously approved file. ValidationAnnotator(file_).update_annotations() return file_
def from_upload(cls, upload, version, platform, is_beta=False, parsed_data=None): if parsed_data is None: parsed_data = {} addon = version.addon file_ = cls(version=version, platform=platform) upload.path = force_bytes(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] file_.no_restart = parsed_data.get('no_restart', False) file_.strict_compatibility = parsed_data.get('strict_compatibility', False) file_.is_multi_package = parsed_data.get('is_multi_package', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) if (is_beta and addon.status == amo.STATUS_PUBLIC and version.channel == amo.RELEASE_CHANNEL_LISTED): file_.status = amo.STATUS_BETA file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file( upload.path, os.path.join(version.path_prefix, nfd_str(file_.filename))) if upload.validation: # Import loop. from olympia.devhub.tasks import annotate_validation_results from olympia.devhub.utils import ValidationAnnotator validation = annotate_validation_results(validation) FileValidation.from_json(file_, validation) # Copy annotations from any previously approved file. ValidationAnnotator(file_).update_annotations() return file_
def save_model(self, request, obj, form, change): super().save_model(request, obj, form, change) size_thumb = (150, 120) size_full = (960, 640) with tempfile.NamedTemporaryFile(dir=settings.TMP_PATH) as tmp: resize_image(obj.custom_image.path, tmp.name, size_thumb, 'jpg') copy_stored_file(tmp.name, obj.thumbnail_path) with tempfile.NamedTemporaryFile(dir=settings.TMP_PATH) as tmp: resize_image(obj.custom_image.path, tmp.name, size_full, 'jpg') copy_stored_file(tmp.name, obj.custom_image.path)
def unhide_disabled_file(self): if not self.filename: return src, dst = self.guarded_file_path, self.file_path self.mv(src, dst, 'Moving undisabled file: %s => %s') # Put files back on the mirrors if necessary. if storage.exists(self.file_path): destinations = [self.version.path_prefix] if self.status in amo.MIRROR_STATUSES: destinations.append(self.version.mirror_path_prefix) for dest in destinations: dest = os.path.join(dest, nfd_str(self.filename)) log.info('Re-mirroring disabled/enabled file to %s' % dest) copy_stored_file(self.file_path, dest)
def file_factory(**kw): version = kw['version'] filename = kw.pop('filename', '%s-%s.xpi' % (version.addon_id, version.id)) status = kw.pop('status', amo.STATUS_APPROVED) file_ = File.objects.create(filename=filename, status=status, **kw) fixture_path = os.path.join(settings.ROOT, 'src/olympia/files/fixtures/files', filename) if os.path.exists(fixture_path): copy_stored_file(fixture_path, file_.current_file_path) return file_
def unhide_disabled_file(self): if not self.filename: return src, dst = self.guarded_file_path, self.file_path self.mv(src, dst, 'Moving undisabled file: %s => %s') # Put files back on the mirrors if necessary. if storage.exists(self.file_path): destinations = [self.version.path_prefix] if self.status in amo.MIRROR_STATUSES: destinations.append(self.version.mirror_path_prefix) for dest in destinations: dest = os.path.join(dest, nfd_str(self.filename)) log.info('Re-mirroring disabled/enabled file to %s' % dest) copy_stored_file(self.file_path, dest)
def from_upload(cls, upload, version, platform, parsed_data=None): """ Create a File instance from a FileUpload, a Version, a platform id and the parsed_data generated by parse_addon(). Note that it's the caller's responsability to ensure the file is valid. We can't check for that here because an admin may have overridden the validation results.""" assert parsed_data is not None file_ = cls(version=version, platform=platform) upload_path = force_text(nfd_str(upload.path)) ext = force_text(os.path.splitext(upload_path)[1]) file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload_path) file_.is_restart_required = parsed_data.get( 'is_restart_required', False) file_.strict_compatibility = parsed_data.get( 'strict_compatibility', False) file_.is_experiment = parsed_data.get('is_experiment', False) file_.is_webextension = parsed_data.get('is_webextension', False) file_.is_mozilla_signed_extension = parsed_data.get( 'is_mozilla_signed_extension', False) file_.hash = file_.generate_hash(upload_path) file_.original_hash = file_.hash file_.save() if file_.is_webextension: permissions = list(parsed_data.get('permissions', [])) # Add content_scripts host matches too. for script in parsed_data.get('content_scripts', []): permissions.extend(script.get('matches', [])) if permissions: WebextPermission.objects.create(permissions=permissions, file=file_) log.info('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. copy_stored_file(upload_path, file_.current_file_path) if upload.validation: validation = json.loads(upload.validation) FileValidation.from_json(file_, validation) return file_
def copy_to_mirror(self): if not self.filename: return try: if storage.exists(self.file_path): dst = self.mirror_file_path if not dst: return log.info('Moving file to mirror: %s => %s' % (self.file_path, dst)) copy_stored_file(self.file_path, dst) except UnicodeEncodeError: log.info('Copy Failure: %s %s %s' % (self.id, smart_str(self.filename), smart_str(self.file_path)))
def copy_to_mirror(self): if not self.filename: return try: if storage.exists(self.file_path): dst = self.mirror_file_path if not dst: return log.info('Moving file to mirror: %s => %s' % (self.file_path, dst)) copy_stored_file(self.file_path, dst) except UnicodeEncodeError: log.info( 'Copy Failure: %s %s %s' % (self.id, smart_str(self.filename), smart_str(self.file_path)))
def file_factory(**kw): version = kw['version'] filename = kw.pop('filename', '%s-%s' % (version.addon_id, version.id)) status = kw.pop('status', amo.STATUS_PUBLIC) platform = kw.pop('platform', amo.PLATFORM_ALL.id) file_ = File.objects.create( filename=filename, platform=platform, status=status, **kw) fixture_path = os.path.join( settings.ROOT, 'src/olympia/files/fixtures/files', filename) if os.path.exists(fixture_path): copy_stored_file(fixture_path, file_.current_file_path) return file_
def file_factory(**kw): version = kw['version'] filename = kw.pop('filename', '%s-%s.xpi' % (version.addon_id, version.id)) status = kw.pop('status', amo.STATUS_APPROVED) platform = kw.pop('platform', amo.PLATFORM_ALL.id) file_ = File.objects.create( filename=filename, platform=platform, status=status, **kw) fixture_path = os.path.join( settings.ROOT, 'src/olympia/files/fixtures/files', filename) if os.path.exists(fixture_path): copy_stored_file(fixture_path, file_.current_file_path) return file_
def test_extract_theme_properties(): addon = addon_factory(type=amo.ADDON_STATICTHEME) result = utils.extract_theme_properties(addon, addon.current_version.channel) assert result == {} # There's no file, but it be should safely handled. # Add the zip in the right place zip_file = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/static_theme.zip') copy_stored_file(zip_file, addon.current_version.all_files[0].file_path) result = utils.extract_theme_properties(addon, addon.current_version.channel) assert result['colors'] == {"accentcolor": "#adb09f", "textcolor": "#000"} assert result['images'] == { "headerURL": '%s%s//%s/%s/%s' % (settings.MEDIA_URL, 'addons', text_type( addon.id), text_type(addon.current_version.id), 'weta.png') }
def test_extract_theme_properties(): addon = addon_factory(type=amo.ADDON_STATICTHEME) result = utils.extract_theme_properties( addon, addon.current_version.channel) assert result == {} # There's no file, but it be should safely handled. # Add the zip in the right place zip_file = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/static_theme.zip') copy_stored_file(zip_file, addon.current_version.all_files[0].file_path) result = utils.extract_theme_properties( addon, addon.current_version.channel) assert result == { "colors": { "accentcolor": "#adb09f", "textcolor": "#000" }, "images": { "headerURL": "weta.png" } }
def approve_rereview(theme): """Replace original theme with pending theme on filesystem.""" # If reuploaded theme, replace old theme design. storage = LocalFileStorage() rereview = theme.rereviewqueuetheme_set.all() reupload = rereview[0] if reupload.header_path != reupload.theme.header_path: create_persona_preview_images( src=reupload.header_path, full_dst=[ reupload.theme.thumb_path, reupload.theme.icon_path], set_modified_on=[reupload.theme.addon]) if not reupload.theme.is_new(): # Legacy themes also need a preview_large.jpg. # Modern themes use preview.png for both thumb and preview so there # is no problem there. copy_stored_file(reupload.theme.thumb_path, reupload.theme.preview_path, storage=storage) move_stored_file( reupload.header_path, reupload.theme.header_path, storage=storage) theme = reupload.theme footer_path = theme.footer_path if reupload.footer_path != footer_path: if not footer_path: dst_root = os.path.join(user_media_path('addons'), str(theme.addon.id)) footer_path = os.path.join(dst_root, 'footer.png') theme.footer = 'footer.png' theme.save() move_stored_file( reupload.footer_path, footer_path, storage=storage) rereview.delete() theme.addon.increment_theme_version_number()
def approve_rereview(theme): """Replace original theme with pending theme on filesystem.""" # If reuploaded theme, replace old theme design. storage = LocalFileStorage() rereview = theme.rereviewqueuetheme_set.all() reupload = rereview[0] if reupload.header_path != reupload.theme.header_path: create_persona_preview_images( src=reupload.header_path, full_dst=[ reupload.theme.thumb_path, reupload.theme.icon_path], set_modified_on=[reupload.theme.addon]) if not reupload.theme.is_new(): # Legacy themes also need a preview_large.jpg. # Modern themes use preview.png for both thumb and preview so there # is no problem there. copy_stored_file(reupload.theme.thumb_path, reupload.theme.preview_path, storage=storage) move_stored_file( reupload.header_path, reupload.theme.header_path, storage=storage) theme = reupload.theme footer_path = theme.footer_path if reupload.footer_path != footer_path: if not footer_path: dst_root = os.path.join(user_media_path('addons'), str(theme.addon.id)) footer_path = os.path.join(dst_root, 'footer.png') theme.footer = 'footer.png' theme.save() move_stored_file( reupload.footer_path, footer_path, storage=storage) rereview.delete() theme.addon.increment_theme_version_number()
def test_copy_chunking(self): src = self.newfile('src.txt', '<contents>') dest = self.path('somedir/dest.txt') copy_stored_file(src, dest, chunk_size=1) assert self.contents(dest) == '<contents>'
def test_non_ascii(self): src = self.newfile(u'kristi\u0107.txt', u'ivan kristi\u0107'.encode('utf8')) dest = self.path(u'somedir/kristi\u0107.txt') copy_stored_file(src, dest) assert self.contents(dest) == 'ivan kristi\xc4\x87'
def test_self_copy(self): src = self.newfile('src.txt', '<contents>') dest = self.path('src.txt') copy_stored_file(src, dest) assert self.contents(dest) == '<contents>'
def test_copy(self): src = self.newfile('src.txt', u'<contents>') dest = self.path('somedir/dest.txt') copy_stored_file(src, dest) assert self.contents(dest) == b'<contents>'
def test_copy_chunking(self): src = self.newfile("src.txt", "<contents>") dest = self.path("somedir/dest.txt") copy_stored_file(src, dest, chunk_size=1) eq_(self.contents(dest), "<contents>")
def test_generate_static_theme_preview_with_chrome_properties( write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [{ 'h': 9, 's': 8, 'l': 7, 'ratio': 0.6 }] theme_manifest = { "images": { "theme_frame": "transparent.gif" }, "colors": { "frame": [123, 45, 67], # 'accentcolor' "tab_background_text": [9, 87, 65], # 'textcolor' "bookmark_text": [0, 0, 0], # 'toolbar_text' } } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join(HEADER_ROOT, 'theme_images.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview(header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview(list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview(single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) colors = [] # check each of our colors above was converted to css codes chrome_colors = { 'bookmark_text': 'toolbar_text', 'frame': 'accentcolor', 'tab_background_text': 'textcolor', } for (chrome_prop, firefox_prop) in chrome_colors.items(): color_list = theme_manifest['colors'][chrome_prop] color = 'rgb(%s,%s,%s)' % tuple(color_list) colors.append('class="%s" fill="%s"' % (firefox_prop, color)) header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] check_render(force_text(header_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 680, 92, 680) check_render(force_text(list_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 760, 92, 760) check_render(force_text(single_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 720, 92, 720)
def test_generate_preview_with_additional_backgrounds( convert_svg_to_png_mock, write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock, ): write_svg_to_png_mock.side_effect = write_empty_png convert_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [{ 'h': 9, 's': 8, 'l': 7, 'ratio': 0.6 }] theme_manifest = { 'images': { 'theme_frame': 'empty.png', 'additional_backgrounds': ['weta_for_tiling.png'], }, 'colors': { 'textcolor': '#123456', # Just textcolor, to test the template defaults and fallbacks. }, 'properties': { 'additional_backgrounds_alignment': ['top'], 'additional_backgrounds_tiling': ['repeat-x'], }, } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/static_theme_tiled.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) # for svg preview we write the svg twice, 1st with write_svg, later with convert_svg assert resize_image_mock.call_count == 2 assert write_svg_to_png_mock.call_count == 2 assert convert_svg_to_png_mock.call_count == 1 assert pngcrush_image_mock.call_count == 1 # First check the firefox Preview is good firefox_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_RENDERINGS['firefox']['position'], ) check_preview( firefox_preview, amo.THEME_PREVIEW_RENDERINGS['firefox'], ) assert write_svg_to_png_mock.call_args_list[0][0][ 1] == firefox_preview.image_path check_thumbnail( firefox_preview, amo.THEME_PREVIEW_RENDERINGS['firefox'], firefox_preview.image_path, resize_image_mock.call_args_list[0], pngcrush_image_mock.call_args_list[0][0], ) # And then the Preview used on AMO amo_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_RENDERINGS['amo']['position'], ) check_preview( amo_preview, amo.THEME_PREVIEW_RENDERINGS['amo'], ) assert convert_svg_to_png_mock.call_args_list[0][0][ 0] == amo_preview.image_path check_thumbnail( amo_preview, amo.THEME_PREVIEW_RENDERINGS['amo'], convert_svg_to_png_mock.call_args_list[0][0][1], resize_image_mock.call_args_list[1], ) # These defaults are mostly defined in the xml template default_colors = ( ('frame', 'fill', 'rgba(229,230,232,1)'), # amo.THEME_FRAME_COLOR_DEFAULT ('tab_background_text', 'fill', '#123456'), # the only one defined in manifest ('bookmark_text', 'fill', '#123456'), # should default to tab_background_text ('toolbar_field', 'fill', 'rgba(255,255,255,1)'), ('toolbar_field_text', 'fill', ''), ('tab_line', 'stroke', 'rgba(0,0,0,0.25)'), ('tab_selected toolbar', 'fill', 'rgba(255,255,255,0.6)'), ) colors = [ f'class="{key} {prop}" {prop}="{color}"' for (key, prop, color) in default_colors ] firefox_svg = write_svg_to_png_mock.call_args_list[0][0][0] interim_amo_svg = write_svg_to_png_mock.call_args_list[1][0][0] with open(amo_preview.image_path) as svg: amo_svg = svg.read() check_render_additional(force_str(firefox_svg), 680, colors) check_render_additional(force_str(interim_amo_svg), 720, transparent_colors) check_render( force_str(amo_svg), 'empty.jpg', 92, 'xMaxYMin slice', 'image/jpeg', True, colors, 720, 92, 720, ) index_addons_mock.assert_called_with([addon.id])
def test_self_copy(self): src = self.newfile("src.txt", "<contents>") dest = self.path("src.txt") copy_stored_file(src, dest) eq_(self.contents(dest), "<contents>")
def test_generate_preview_with_additional_backgrounds( write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [{ 'h': 9, 's': 8, 'l': 7, 'ratio': 0.6 }] theme_manifest = { "images": { "theme_frame": "empty.png", "additional_backgrounds": ["weta_for_tiling.png"], }, "colors": { "textcolor": "#123456", # Just textcolor, to test the template defaults and fallbacks. }, "properties": { "additional_backgrounds_alignment": ["top"], "additional_backgrounds_tiling": ["repeat-x"], }, } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/static_theme_tiled.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview(header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview(list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview(single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) # These defaults are mostly defined in the xml template default_colors = { "frame": "rgba(229,230,232,1)", # amo.THEME_FRAME_COLOR_DEFAULT "tab_background_text": "#123456", # the only one defined in 'manifest' "bookmark_text": "#123456", # should default to tab_background_text "toolbar_field": "rgba(255,255,255,1)", "toolbar_field_text": "", "tab_line": "rgba(0,0,0,0.25)", "tab_selected": "rgba(0,0,0,0)", } colors = [ 'class="%s" fill="%s"' % (key, color) for (key, color) in default_colors.items() ] header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] check_render_additional(force_text(header_svg), 680, colors) check_render_additional(force_text(list_svg), 760, colors) check_render_additional(force_text(single_svg), 720, colors) index_addons_mock.assert_called_with([addon.id])
def from_upload(cls, upload, version, platform, is_beta=False, parse_data={}): addon = version.addon file_ = cls(version=version, platform=platform) upload.path = smart_path(nfd_str(upload.path)) ext = os.path.splitext(upload.path)[1] if ext == '.jar': ext = '.xpi' file_.filename = file_.generate_filename(extension=ext or '.xpi') # Size in bytes. file_.size = storage.size(upload.path) data = cls.get_jetpack_metadata(upload.path) if 'sdkVersion' in data and data['sdkVersion']: file_.jetpack_version = data['sdkVersion'][:10] if file_.jetpack_version: Tag(tag_text='jetpack').save_tag(addon) file_.no_restart = parse_data.get('no_restart', False) file_.strict_compatibility = parse_data.get('strict_compatibility', False) file_.is_multi_package = parse_data.get('is_multi_package', False) file_.is_experiment = parse_data.get('is_experiment', False) file_.is_webextension = parse_data.get('is_webextension', False) if is_beta and addon.status == amo.STATUS_PUBLIC: file_.status = amo.STATUS_BETA elif addon.trusted: # New files in trusted add-ons automatically receive the correct # approved status for their review class. if addon.status == amo.STATUS_PUBLIC: file_.status = amo.STATUS_PUBLIC elif addon.status in amo.LITE_STATUSES: file_.status = amo.STATUS_LITE file_.hash = file_.generate_hash(upload.path) file_.original_hash = file_.hash if upload.validation: validation = json.loads(upload.validation) if validation['metadata'].get('requires_chrome'): file_.requires_chrome = True file_.save() log.debug('New file: %r from %r' % (file_, upload)) # Move the uploaded file from the temp location. destinations = [version.path_prefix] if file_.status in amo.MIRROR_STATUSES: destinations.append(version.mirror_path_prefix) for dest in destinations: copy_stored_file(upload.path, os.path.join(dest, nfd_str(file_.filename))) if upload.validation: # Import loop. from olympia.devhub.tasks import annotate_validation_results from olympia.devhub.utils import ValidationAnnotator validation = annotate_validation_results(validation) FileValidation.from_json(file_, validation) # Copy annotations from any previously approved file. ValidationAnnotator(file_).update_annotations() return file_
def test_self_copy(self): src = self.newfile('src.txt', '<contents>') dest = self.path('src.txt') copy_stored_file(src, dest) assert self.contents(dest) == '<contents>'
def test_copy_chunking(self): src = self.newfile('src.txt', '<contents>') dest = self.path('somedir/dest.txt') copy_stored_file(src, dest, chunk_size=1) assert self.contents(dest) == '<contents>'
def test_non_ascii(self): src = self.newfile(u'kristi\u0107.txt', u'ivan kristi\u0107'.encode('utf8')) dest = self.path(u'somedir/kristi\u0107.txt') copy_stored_file(src, dest) assert self.contents(dest) == 'ivan kristi\xc4\x87'
def test_generate_static_theme_preview_with_alternative_properties( convert_svg_to_png_mock, write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock, manifest_images, manifest_colors, svg_colors, ): write_svg_to_png_mock.side_effect = write_empty_png convert_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [{ 'h': 9, 's': 8, 'l': 7, 'ratio': 0.6 }] theme_manifest = { 'images': manifest_images, 'colors': manifest_colors, } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join(HEADER_ROOT, 'theme_images.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) # for svg preview we write the svg twice, 1st with write_svg, later with convert_svg assert resize_image_mock.call_count == 2 assert write_svg_to_png_mock.call_count == 2 assert convert_svg_to_png_mock.call_count == 1 assert pngcrush_image_mock.call_count == 1 # First check the firefox Preview is good firefox_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_RENDERINGS['firefox']['position'], ) check_preview( firefox_preview, amo.THEME_PREVIEW_RENDERINGS['firefox'], ) assert write_svg_to_png_mock.call_args_list[0][0][ 1] == firefox_preview.image_path check_thumbnail( firefox_preview, amo.THEME_PREVIEW_RENDERINGS['firefox'], firefox_preview.image_path, resize_image_mock.call_args_list[0], pngcrush_image_mock.call_args_list[0][0], ) # And then the Preview used on AMO amo_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_RENDERINGS['amo']['position'], ) check_preview( amo_preview, amo.THEME_PREVIEW_RENDERINGS['amo'], ) assert convert_svg_to_png_mock.call_args_list[0][0][ 0] == amo_preview.image_path check_thumbnail( amo_preview, amo.THEME_PREVIEW_RENDERINGS['amo'], convert_svg_to_png_mock.call_args_list[0][0][1], resize_image_mock.call_args_list[1], ) colors = [ 'class="%(field)s %(prop)s" %(prop)s="%(color)s"' % { 'field': key, 'prop': 'stroke' if key == 'tab_line' else 'fill', 'color': color, } for (key, color) in svg_colors.items() ] firefox_svg = write_svg_to_png_mock.call_args_list[0][0][0] interim_amo_svg = write_svg_to_png_mock.call_args_list[1][0][0] with open(amo_preview.image_path) as svg: amo_svg = svg.read() check_render( force_str(firefox_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 680, 92, 680, ) check_render( force_str(interim_amo_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, transparent_colors, 720, 92, 720, ) check_render( force_str(amo_svg), 'empty.jpg', 92, 'xMaxYMin slice', 'image/jpeg', True, colors, 720, 92, 720, )
def _mock_xpi_side_effect(self, addon, destination): xpi_path = os.path.join( settings.ROOT, 'src/olympia/files/fixtures/files/dict-webext.xpi') copy_stored_file(xpi_path, destination) assert not os.path.isdir(destination) return mock.DEFAULT
def test_generate_static_theme_preview( write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock, header_url, header_height, preserve_aspect_ratio, mimetype, valid_img): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [ {'h': 9, 's': 8, 'l': 7, 'ratio': 0.6} ] theme_manifest = { "images": { }, "colors": { "frame": "#918e43", "tab_background_text": "#3deb60", "bookmark_text": "#b5ba5b", "toolbar_field": "#cc29cc", "toolbar_field_text": "#17747d", "tab_line": "#00db12", "tab_selected": "#40df39", } } if header_url is not None: theme_manifest['images']['theme_frame'] = header_url addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join(HEADER_ROOT, 'theme_images.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview( header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview( list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview( single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) # Now check the svg renders header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] colors = ['class="%s" fill="%s"' % (key, color) for (key, color) in theme_manifest['colors'].items()] preserve_aspect_ratio = ( (preserve_aspect_ratio, ) * 3 if not isinstance(preserve_aspect_ratio, tuple) else preserve_aspect_ratio) check_render(force_text(header_svg), header_url, header_height, preserve_aspect_ratio[0], mimetype, valid_img, colors, 680, 92, 680) check_render(force_text(list_svg), header_url, header_height, preserve_aspect_ratio[1], mimetype, valid_img, colors, 760, 92, 760) check_render(force_text(single_svg), header_url, header_height, preserve_aspect_ratio[2], mimetype, valid_img, colors, 720, 92, 720) index_addons_mock.assert_called_with([addon.id])
def test_generate_static_theme_preview_with_alternative_properties( write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock, manifest_images, manifest_colors, svg_colors): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [{ 'h': 9, 's': 8, 'l': 7, 'ratio': 0.6 }] theme_manifest = { "images": manifest_images, "colors": manifest_colors, } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join(HEADER_ROOT, 'theme_images.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview(header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview(list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview(single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) colors = [ 'class="%s" fill="%s"' % (key, color) for (key, color) in svg_colors.items() ] header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] check_render(force_text(header_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 680, 92, 680) check_render(force_text(list_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 760, 92, 760) check_render(force_text(single_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 720, 92, 720)
def test_generate_preview_with_additional_backgrounds( write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [ {'h': 9, 's': 8, 'l': 7, 'ratio': 0.6} ] theme_manifest = { "images": { "theme_frame": "empty.png", "additional_backgrounds": ["weta_for_tiling.png"], }, "colors": { "textcolor": "#123456", # Just textcolor, to test the template defaults and fallbacks. }, "properties": { "additional_backgrounds_alignment": ["top"], "additional_backgrounds_tiling": ["repeat-x"], }, } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join( settings.ROOT, 'src/olympia/devhub/tests/addons/static_theme_tiled.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview( header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview( list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview( single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) # These defaults are mostly defined in the xml template default_colors = { "frame": "rgba(229,230,232,1)", # amo.THEME_FRAME_COLOR_DEFAULT "tab_background_text": "#123456", # the only one defined in 'manifest' "bookmark_text": "#123456", # should default to tab_background_text "toolbar_field": "rgba(255,255,255,1)", "toolbar_field_text": "", "tab_line": "rgba(0,0,0,0.25)", "tab_selected": "rgba(0,0,0,0)", } colors = ['class="%s" fill="%s"' % (key, color) for (key, color) in default_colors.items()] header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] check_render_additional(force_text(header_svg), 680, colors) check_render_additional(force_text(list_svg), 760, colors) check_render_additional(force_text(single_svg), 720, colors) index_addons_mock.assert_called_with([addon.id])
def test_generate_static_theme_preview(write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock, header_url, header_height, preserve_aspect_ratio, mimetype, valid_img): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [{ 'h': 9, 's': 8, 'l': 7, 'ratio': 0.6 }] theme_manifest = { "images": {}, "colors": { "frame": "#918e43", "tab_background_text": "#3deb60", "bookmark_text": "#b5ba5b", "toolbar_field": "#cc29cc", "toolbar_field_text": "#17747d", "tab_line": "#00db12", "tab_selected": "#40df39", } } if header_url is not None: theme_manifest['images']['theme_frame'] = header_url addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join(HEADER_ROOT, 'theme_images.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview(header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview(list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview(single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) # Now check the svg renders header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] colors = [ 'class="%s" fill="%s"' % (key, color) for (key, color) in theme_manifest['colors'].items() ] preserve_aspect_ratio = ((preserve_aspect_ratio, ) * 3 if not isinstance(preserve_aspect_ratio, tuple) else preserve_aspect_ratio) check_render(force_text(header_svg), header_url, header_height, preserve_aspect_ratio[0], mimetype, valid_img, colors, 680, 92, 680) check_render(force_text(list_svg), header_url, header_height, preserve_aspect_ratio[1], mimetype, valid_img, colors, 760, 92, 760) check_render(force_text(single_svg), header_url, header_height, preserve_aspect_ratio[2], mimetype, valid_img, colors, 720, 92, 720) index_addons_mock.assert_called_with([addon.id])
def test_generate_static_theme_preview_with_alternative_properties( write_svg_to_png_mock, resize_image_mock, pngcrush_image_mock, extract_colors_from_image_mock, index_addons_mock, manifest_images, manifest_colors, svg_colors): write_svg_to_png_mock.return_value = True extract_colors_from_image_mock.return_value = [ {'h': 9, 's': 8, 'l': 7, 'ratio': 0.6} ] theme_manifest = { "images": manifest_images, "colors": manifest_colors, } addon = addon_factory() destination = addon.current_version.all_files[0].current_file_path zip_file = os.path.join(HEADER_ROOT, 'theme_images.zip') copy_stored_file(zip_file, destination) generate_static_theme_preview(theme_manifest, addon.current_version.pk) assert resize_image_mock.call_count == 3 assert write_svg_to_png_mock.call_count == 3 assert pngcrush_image_mock.call_count == 3 # First check the header Preview is good header_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['header']['position']) check_preview( header_preview, amo.THEME_PREVIEW_SIZES['header'], write_svg_to_png_mock.call_args_list[0][0], resize_image_mock.call_args_list[0][0], pngcrush_image_mock.call_args_list[0][0]) # Then the list Preview list_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['list']['position']) check_preview( list_preview, amo.THEME_PREVIEW_SIZES['list'], write_svg_to_png_mock.call_args_list[1][0], resize_image_mock.call_args_list[1][0], pngcrush_image_mock.call_args_list[1][0]) # And finally the new single Preview single_preview = VersionPreview.objects.get( version=addon.current_version, position=amo.THEME_PREVIEW_SIZES['single']['position']) check_preview( single_preview, amo.THEME_PREVIEW_SIZES['single'], write_svg_to_png_mock.call_args_list[2][0], resize_image_mock.call_args_list[2][0], pngcrush_image_mock.call_args_list[2][0]) colors = ['class="%s" fill="%s"' % (key, color) for (key, color) in svg_colors.items()] header_svg = write_svg_to_png_mock.call_args_list[0][0][0] list_svg = write_svg_to_png_mock.call_args_list[1][0][0] single_svg = write_svg_to_png_mock.call_args_list[2][0][0] check_render(force_text(header_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 680, 92, 680) check_render(force_text(list_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 760, 92, 760) check_render(force_text(single_svg), 'transparent.gif', 1, 'xMaxYMin meet', 'image/gif', True, colors, 720, 92, 720)
def test_non_ascii(self): src = self.newfile(u"kristi\u0107.txt", u"ivan kristi\u0107".encode("utf8")) dest = self.path(u"somedir/kristi\u0107.txt") copy_stored_file(src, dest) eq_(self.contents(dest), "ivan kristi\xc4\x87")
def _mock_xpi_side_effect(self, addon, destination): xpi_path = os.path.join( settings.ROOT, 'src/olympia/files/fixtures/files/dict-webext.xpi') copy_stored_file(xpi_path, destination) assert not os.path.isdir(destination) return mock.DEFAULT