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): class EditSupplierPartForm(HelperForm):
""" Form for editing a SupplierPart object """ """ Form for editing a SupplierPart object """

View File

@ -2,14 +2,19 @@
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load inventree_extras %}
{% block page_title %} {% block page_title %}
InvenTree | {% trans "Company" %} - {{ company.name }} InvenTree | {% trans "Company" %} - {{ company.name }}
{% endblock %} {% endblock %}
{% block thumbnail %} {% block thumbnail %}
{% settings_value "INVENTREE_DOWNLOAD_FROM_URL" as allow_download %}
<div class='dropzone part-thumb-container' id='company-thumb'> <div class='dropzone part-thumb-container' id='company-thumb'>
<img class="part-thumb" <img class="part-thumb" id='company-image'
{% if company.image %} {% if company.image %}
src="{{ company.image.url }}" src="{{ company.image.url }}"
{% else %} {% else %}
@ -18,6 +23,9 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
<div class='btn-row part-thumb-overlay'> <div class='btn-row part-thumb-overlay'>
<div class='btn-group'> <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> <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> </div>
</div> </div>
@ -141,7 +149,7 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
); );
{% if company.image %} {% if company.image %}
$('#company-thumb').click(function() { $('#company-image').click(function() {
showModalImage('{{ company.image.url }}'); showModalImage('{{ company.image.url }}');
}); });
{% endif %} {% 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 %} {% endblock %}

View File

@ -21,6 +21,7 @@ company_detail_urls = [
url(r'^notes/', views.CompanyNotes.as_view(), name='company-notes'), url(r'^notes/', views.CompanyNotes.as_view(), name='company-notes'),
url(r'^thumbnail/', views.CompanyImage.as_view(), name='company-image'), 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 # Any other URL
url(r'^.*$', views.CompanyDetail.as_view(), name='company-detail'), 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.urls import reverse
from django.forms import HiddenInput from django.forms import HiddenInput
from django.core.files.base import ContentFile
from moneyed import CURRENCIES from moneyed import CURRENCIES
from PIL import Image
import requests
import io
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.helpers import str2bool from InvenTree.helpers import str2bool
from InvenTree.views import InvenTreeRoleMixin from InvenTree.views import InvenTreeRoleMixin
@ -28,6 +33,7 @@ from .forms import EditCompanyForm
from .forms import CompanyImageForm from .forms import CompanyImageForm
from .forms import EditSupplierPartForm from .forms import EditSupplierPartForm
from .forms import EditPriceBreakForm from .forms import EditPriceBreakForm
from .forms import CompanyImageDownloadForm
import common.models import common.models
import common.settings import common.settings
@ -150,6 +156,84 @@ class CompanyDetail(DetailView):
return ctx 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): class CompanyImage(AjaxUpdateView):
""" View for uploading an image for the Company """ """ View for uploading an image for the Company """
model = Company model = Company

View File

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

View File

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