Add image download functionality for company

This commit is contained in:
Oliver Walters 2021-03-18 09:20:24 +11:00
parent 4e7243b999
commit 9c91ba4692
7 changed files with 129 additions and 5 deletions

View File

@ -66,6 +66,24 @@ class CompanyImageForm(HelperForm):
]
class CompanyImageDownloadForm(HelperForm):
"""
Form for downloading an image from a URL
"""
url = django.forms.URLField(
label=_('URL'),
help_text=_('Image URL'),
required=True
)
class Meta:
model = Company
fields = [
'url',
]
class EditSupplierPartForm(HelperForm):
""" Form for editing a SupplierPart object """

View File

@ -2,14 +2,19 @@
{% load static %}
{% load i18n %}
{% load inventree_extras %}
{% block page_title %}
InvenTree | {% trans "Company" %} - {{ company.name }}
{% endblock %}
{% block thumbnail %}
{% settings_value "INVENTREE_DOWNLOAD_FROM_URL" as allow_download %}
<div class='dropzone part-thumb-container' id='company-thumb'>
<img class="part-thumb"
<img class="part-thumb" id='company-image'
{% if company.image %}
src="{{ company.image.url }}"
{% else %}
@ -18,6 +23,9 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
<div class='btn-row part-thumb-overlay'>
<div class='btn-group'>
<button type='button' class='btn btn-default btn-glyph' title='{% trans "Upload new image" %}' id='company-image-upload'><span class='fas fa-file-upload'></span></button>
{% if allow_download %}
<button type='button' class='btn btn-default btn-glyph' title="{% trans 'Download image from URL' %}" id='company-image-url'><span class='fas fa-cloud-download-alt'></span></button>
{% endif %}
</div>
</div>
</div>
@ -141,7 +149,7 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
);
{% if company.image %}
$('#company-thumb').click(function() {
$('#company-image').click(function() {
showModalImage('{{ company.image.url }}');
});
{% endif %}
@ -155,4 +163,17 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
);
});
{% settings_value "INVENTREE_DOWNLOAD_FROM_URL" as allow_download %}
{% if allow_download %}
$('#company-image-url').click(function() {
launchModalForm(
'{% url "company-image-download" company.id %}',
{
reload: true,
}
)
});
{% endif %}
{% endblock %}

View File

@ -21,6 +21,7 @@ company_detail_urls = [
url(r'^notes/', views.CompanyNotes.as_view(), name='company-notes'),
url(r'^thumbnail/', views.CompanyImage.as_view(), name='company-image'),
url(r'^thumb-download/', views.CompanyImageDownloadFromURL.as_view(), name='company-image-download'),
# Any other URL
url(r'^.*$', views.CompanyDetail.as_view(), name='company-detail'),

View File

@ -11,9 +11,14 @@ from django.views.generic import DetailView, ListView, UpdateView
from django.urls import reverse
from django.forms import HiddenInput
from django.core.files.base import ContentFile
from moneyed import CURRENCIES
from PIL import Image
import requests
import io
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.helpers import str2bool
from InvenTree.views import InvenTreeRoleMixin
@ -28,6 +33,7 @@ from .forms import EditCompanyForm
from .forms import CompanyImageForm
from .forms import EditSupplierPartForm
from .forms import EditPriceBreakForm
from .forms import CompanyImageDownloadForm
import common.models
import common.settings
@ -150,6 +156,84 @@ class CompanyDetail(DetailView):
return ctx
class CompanyImageDownloadFromURL(AjaxUpdateView):
"""
View for downloading an image from a provided URL
"""
model = Company
ajax_template_name = 'image_download.html'
form_class = CompanyImageDownloadForm
ajax_form_title = _('Download Image')
def validate(self, company, form):
"""
Validate that the image data are correct
"""
# First ensure that the normal validation routines pass
if not form.is_valid():
return
# We can now extract a valid URL from the form data
url = form.cleaned_data.get('url', None)
# Download the file
response = requests.get(url, stream=True)
# Look at response header, reject if too large
content_length = response.headers.get('Content-Length', '0')
try:
content_length = int(content_length)
except (ValueError):
# If we cannot extract meaningful length, just assume it's "small enough"
content_length = 0
# TODO: Factor this out into a configurable setting
MAX_IMG_LENGTH = 10 * 1024 * 1024
if content_length > MAX_IMG_LENGTH:
form.add_error('url', _('Image size exceeds maximum allowable size for download'))
return
self.response = response
# Check for valid response code
if not response.status_code == 200:
form.add_error('url', f"{_('Invalid response')}: {response.status_code}")
return
response.raw.decode_content = True
try:
self.image = Image.open(response.raw).convert()
self.image.verify()
except:
form.add_error('url', _("Supplied URL is not a valid image file"))
return
def save(self, company, form, **kwargs):
"""
Save the downloaded image to the company
"""
fmt = self.image.format
if not fmt:
fmt = 'PNG'
buffer = io.BytesIO()
self.image.save(buffer, format=fmt)
# Construct a simplified name for the image
filename = f"company_{company.pk}_image.{fmt.lower()}"
company.image.save(
filename,
ContentFile(buffer.getvalue()),
)
class CompanyImage(AjaxUpdateView):
""" View for uploading an image for the Company """
model = Company

View File

@ -7,7 +7,7 @@
<div class="media">
<div class="media-left part-thumb-container">
<div class='dropzone' id='part-thumb'>
<img class="part-thumb"
<img class="part-thumb" id='part-image'
{% if part.image %}
src="{{ part.image.url }}"
{% else %}

View File

@ -843,7 +843,7 @@ class PartImageDownloadFromURL(AjaxUpdateView):
model = Part
ajax_template_name = 'part/image_download.html'
ajax_template_name = 'image_download.html'
form_class = part_forms.PartImageDownloadForm
ajax_form_title = _('Download Image')
@ -890,7 +890,7 @@ class PartImageDownloadFromURL(AjaxUpdateView):
response.raw.decode_content = True
try:
self.image = Image.open(response.raw).convert('RGB')
self.image = Image.open(response.raw).convert()
self.image.verify()
except:
form.add_error('url', _("Supplied URL is not a valid image file"))