def upload_image()

in src/olympia/devhub/views.py [0:0]


def upload_image(request, addon_id, addon, upload_type):
    errors = []
    upload_hash = ''
    if 'upload_image' in request.FILES:
        upload_preview = request.FILES['upload_image']
        upload_preview.seek(0)

        upload_hash = uuid4().hex
        loc = os.path.join(settings.TMP_PATH, upload_type, upload_hash)

        with storage.open(loc, 'wb') as fd:
            for chunk in upload_preview:
                fd.write(chunk)

        is_icon = upload_type == 'icon'
        is_preview = upload_type == 'preview'
        image_check = amo_utils.ImageCheck(upload_preview)
        is_animated = image_check.is_animated()  # will also cache .is_image()

        if (
            upload_preview.content_type not in amo.IMG_TYPES
            or not image_check.is_image()
        ):
            if is_icon:
                errors.append(gettext('Icons must be either PNG or JPG.'))
            else:
                errors.append(gettext('Images must be either PNG or JPG.'))

        if is_animated:
            if is_icon:
                errors.append(gettext('Icons cannot be animated.'))
            else:
                errors.append(gettext('Images cannot be animated.'))

        if is_icon:
            max_size = settings.MAX_ICON_UPLOAD_SIZE
        else:
            max_size = settings.MAX_IMAGE_UPLOAD_SIZE

        if upload_preview.size > max_size:
            errors.append(
                gettext('Please use images smaller than %dMB.')
                % (max_size // 1024 // 1024)
            )

        content_waffle = waffle.switch_is_active('content-optimization')
        if image_check.is_image() and content_waffle and is_preview:
            min_size = amo.ADDON_PREVIEW_SIZES.get('min')
            # * 100 to get a nice integer to compare against rather than 1.3333
            required_ratio = min_size[0] * 100 // min_size[1]
            actual_size = image_check.size
            actual_ratio = actual_size[0] * 100 // actual_size[1]
            if actual_size[0] < min_size[0] or actual_size[1] < min_size[1]:
                # L10n: {0} is an image width (in pixels), {1} is a height.
                errors.append(
                    gettext(
                        'Image must be at least {0} pixels wide and {1} pixels tall.'
                    ).format(min_size[0], min_size[1])
                )
            if actual_ratio != required_ratio:
                errors.append(gettext('Image dimensions must be in the ratio 4:3.'))

        if image_check.is_image() and content_waffle and is_icon:
            standard_size = amo.ADDON_ICON_SIZES[-1]
            icon_size = image_check.size
            if icon_size[0] < standard_size or icon_size[1] < standard_size:
                # L10n: {0} is an image width/height (in pixels).
                errors.append(
                    gettext('Icon must be at least {0} pixels wide and tall.').format(
                        standard_size
                    )
                )
            if icon_size[0] != icon_size[1]:
                errors.append(gettext('Icon must be square (same width and height).'))

        if errors and is_preview and os.path.exists(loc):
            # Delete the temporary preview file in case of error.
            os.unlink(loc)
    else:
        errors.append(gettext('There was an error uploading your preview.'))

    if errors:
        upload_hash = ''

    return {'upload_hash': upload_hash, 'errors': errors}