diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 2843dc4eb8..e14efd5298 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -5,11 +5,21 @@ Provides helper functions used throughout the InvenTree project import io import json from datetime import datetime +from PIL import Image from wsgiref.util import FileWrapper from django.http import StreamingHttpResponse +def TestIfImage(img): + """ Test if an image file is indeed an image """ + try: + Image.open(img).verify() + return True + except: + return False + + def str2bool(text, test=True): """ Test if a string 'looks' like a boolean value. diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index e97386d229..1b2814ba52 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -78,7 +78,6 @@ class EditPartForm(HelperForm): 'purchaseable', 'salable', 'notes', - 'image', ] diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index a99839d34a..a59b97ce47 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -153,7 +153,7 @@ { accept_text: 'Activate', accept: function() { - inventreeUpdate( + inventreePut( "{% url 'api-part-detail' part.id %}", { active: true, @@ -176,7 +176,7 @@ { accept_text: 'Deactivate', accept: function() { - inventreeUpdate( + inventreePut( "{% url 'api-part-detail' part.id %}", { active: false, diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index 8abf7717f3..29e1638d55 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -108,47 +108,22 @@ var files = transfer.files; - console.log('dropped'); - if (files.length > 0) { var file = files[0]; - var formData = new FormData(); - - var token = getCookie('csrftoken'); - - formData.append('file', file); - - $.ajax({ - beforeSend: function(xhr, settings) { - xhr.setRequestHeader('X-CSRFToken', token); - }, - url: "{% url 'part-image-upload' part.id %}", - type: 'POST', - data: formData, - processData: false, - contentType: false, - success: function(data, status, xhr) { - //location.reload(); - }, - error: function(xhr, status, error) { - console.log('Error uploading thumbnail: ' + status); - console.log(error); - } - }); - - /* - inventreeUpdate( + inventreeFileUpload( "{% url 'part-image-upload' part.id %}", - formData, + file, + {}, { - method: 'POST', - dataType: 'json', + success: function(data, status, xhr) { + location.reload(); + }, + error: function(xhr, status, error) { + showAlertDialog('Error uploading image', renderErrorMessage(xhr)); + } } ); - */ - - console.log('submitted'); } }); diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 6fbd18318e..1bfef2962a 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -30,7 +30,7 @@ from .forms import EditSupplierPartForm from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView from InvenTree.views import QRCodeView -from InvenTree.helpers import DownloadFile, str2bool +from InvenTree.helpers import DownloadFile, str2bool, TestIfImage class PartIndex(ListView): @@ -275,22 +275,29 @@ class UploadPartImage(AjaxView): model = Part def post(self, request, *args, **kwargs): + + response = {} + status = 200 + try: part = Part.objects.get(pk=kwargs.get('pk')) except Part.DoesNotExist: - error_dict = { - 'error': 'Part not found', - } + response['error'] = 'Part not found' return JsonResponse(error_dict, status=404) - print("Files:", request.FILES) uploaded_file = request.FILES['file'] - response_dict = { - 'success': 'File was uploaded successfully', - } + if TestIfImage(uploaded_file): + part.image = uploaded_file + part.clean() + part.save() - return JsonResponse(response_dict, status=200) + response['success'] = 'File was uploaded successfully' + else: + response['error'] = 'Not a valid image file' + status = 400 + + return JsonResponse(response, status=status) diff --git a/InvenTree/static/script/inventree/api.js b/InvenTree/static/script/inventree/api.js index 27feec8b79..015186d83b 100644 --- a/InvenTree/static/script/inventree/api.js +++ b/InvenTree/static/script/inventree/api.js @@ -42,7 +42,49 @@ function inventreeGet(url, filters={}, options={}) { }); } -function inventreeUpdate(url, data={}, options={}) { +function inventreeFileUpload(url, file, data={}, options={}) { + /* Upload a file via AJAX using the FormData approach. + * + * Note that the following AJAX parameters are required for FormData upload + * + * processData: false + * contentType: false + */ + + // CSRF cookie token + var csrftoken = getCookie('csrftoken'); + + var data = new FormData(); + + data.append('file', file); + + return $.ajax({ + beforeSend: function(xhr, settings) { + xhr.setRequestHeader('X-CSRFToken', csrftoken); + }, + url: url, + method: 'POST', + data: data, + processData: false, + contentType: false, + success: function(data, status, xhr) { + console.log('Uploaded file - ' + file.name); + + if (options.success) { + options.success(data, status, xhr); + } + }, + error: function(xhr, status, error) { + console.log('Error uploading file: ' + status); + + if (options.error) { + options.error(xhr, status, error); + } + } + }); +} + +function inventreePut(url, data={}, options={}) { var method = options.method || 'PUT'; @@ -93,9 +135,9 @@ function getCompanies(filters={}, options={}) { } function updateStockItem(pk, data, final=false) { - return inventreeUpdate('/api/stock/' + pk + '/', data, final); + return inventreePut('/api/stock/' + pk + '/', data, final); } function updatePart(pk, data, final=false) { - return inventreeUpdate('/api/part/' + pk + '/', data, final); + return inventreePut('/api/part/' + pk + '/', data, final); } \ No newline at end of file diff --git a/InvenTree/static/script/inventree/part.js b/InvenTree/static/script/inventree/part.js index 7682d5a6c1..c3b0f8182d 100644 --- a/InvenTree/static/script/inventree/part.js +++ b/InvenTree/static/script/inventree/part.js @@ -41,7 +41,7 @@ function toggleStar(options) { if (response.length == 0) { // Zero length response = star does not exist // So let's add one! - inventreeUpdate( + inventreePut( url, { part: options.part, @@ -57,7 +57,7 @@ function toggleStar(options) { } else { var pk = response[0].pk; // There IS a star (delete it!) - inventreeUpdate( + inventreePut( url + pk + "/", { }, diff --git a/InvenTree/static/script/inventree/stock.js b/InvenTree/static/script/inventree/stock.js index 73199466f6..71bbed2ab3 100644 --- a/InvenTree/static/script/inventree/stock.js +++ b/InvenTree/static/script/inventree/stock.js @@ -141,7 +141,7 @@ function updateStock(items, options={}) { return false; } - inventreeUpdate("/api/stock/stocktake/", + inventreePut("/api/stock/stocktake/", { 'action': options.action, 'items[]': stocktake, @@ -226,7 +226,7 @@ function moveStockItems(items, options) { } function doMove(location, parts, notes) { - inventreeUpdate("/api/stock/move/", + inventreePut("/api/stock/move/", { location: location, 'parts[]': parts,