diff --git a/cookbook/migrations/0067_auto_20200629_1508.py b/cookbook/migrations/0067_auto_20200629_1508.py new file mode 100644 index 000000000..51991bb85 --- /dev/null +++ b/cookbook/migrations/0067_auto_20200629_1508.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.7 on 2020-06-29 13:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0066_auto_20200626_1455'), + ] + + operations = [ + migrations.AlterField( + model_name='ingredient', + name='note', + field=models.CharField(blank=True, max_length=256, null=True), + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index b4abeeb93..36b162504 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -149,7 +149,7 @@ class Ingredient(models.Model): food = models.ForeignKey(Food, on_delete=models.PROTECT) unit = models.ForeignKey(Unit, on_delete=models.PROTECT) amount = models.DecimalField(default=0, decimal_places=16, max_digits=32) - note = models.CharField(max_length=64, null=True, blank=True) + note = models.CharField(max_length=256, null=True, blank=True) order = models.IntegerField(default=0) def __str__(self): diff --git a/cookbook/serializer.py b/cookbook/serializer.py index d9c09a479..7a311e011 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -99,8 +99,14 @@ class RecipeSerializer(WritableNestedModelSerializer): class Meta: model = Recipe - fields = '__all__' - validators = [] + fields = ['name', 'image', 'keywords', 'steps', 'working_time', 'waiting_time', 'created_by', 'created_at', 'updated_at', 'internal'] + read_only_fields = ['image', 'created_by', 'created_at'] + + +class RecipeImageSerializer(WritableNestedModelSerializer): + class Meta: + model = Recipe + fields = ['image', ] class RecipeImportSerializer(serializers.ModelSerializer): diff --git a/cookbook/templates/forms/edit_internal_recipe.html b/cookbook/templates/forms/edit_internal_recipe.html index d50fdaaf0..24d3122e7 100644 --- a/cookbook/templates/forms/edit_internal_recipe.html +++ b/cookbook/templates/forms/edit_internal_recipe.html @@ -50,15 +50,17 @@
- Image Edit Placeholder + +
- +
- +
- -
{% trans 'Save & View' %} + {% trans 'View Recipe' %}

@@ -257,7 +240,8 @@ }) }, updateRecipe: function (view_after) { - this.$http.put("{% url 'api:recipe-detail' recipe.pk %}", this.recipe).then((response) => { + this.$http.put("{% url 'api:recipe-detail' recipe.pk %}", this.recipe, + {}).then((response) => { console.log(view_after) console.log(response) if (view_after) { @@ -266,6 +250,28 @@ }).catch((err) => { console.log(err) }) + }, + imageChanged: function (event) { + if (event.target.files && event.target.files[0]) { + let fd = new FormData() + fd.append('image', event.target.files[0]) + this.$http.put("{% url 'api:recipe-detail' recipe.pk %}" + 'image/', fd, + {headers: {'Content-Type': 'multipart/form-data'}}).then((response) => { + console.log(response) + + }).catch((err) => { + console.log(err) + }) + + + let reader = new FileReader(); + reader.onload = function (e) { + $('#id_image').attr('src', e.target.result); + } + reader.readAsDataURL(event.target.files[0]); + } + + }, addStep: function () { //TODO see if default can be generated from options request this.recipe.steps.push( @@ -290,7 +296,6 @@ if (confirm('{% trans 'Are you sure that you want to delete this ingredient?' %}')) { step.ingredients = step.ingredients.filter(item => item !== ingredient) } - }, searchKeywords: function (query) { this.keywords_loading = true diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 2850ffbad..9351dd6ac 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -1,20 +1,25 @@ import io import json import re +import uuid import requests +from PIL import Image from annoying.decorators import ajax_request from annoying.functions import get_object_or_None from django.contrib import messages from django.contrib.auth.models import User +from django.core.files import File from django.db.models import Q from django.http import HttpResponse, FileResponse, JsonResponse from django.shortcuts import redirect from django.utils.translation import gettext as _ from icalendar import Calendar, Event -from rest_framework import viewsets, permissions +from rest_framework import viewsets, permissions, decorators from rest_framework.exceptions import APIException from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, ListModelMixin +from rest_framework.parsers import JSONParser, FileUploadParser, MultiPartParser +from rest_framework.response import Response from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser from cookbook.helper.recipe_url_import import get_from_html @@ -22,7 +27,7 @@ from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, from cookbook.provider.dropbox import Dropbox from cookbook.provider.nextcloud import Nextcloud from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \ - KeywordSerializer + KeywordSerializer, RecipeImageSerializer class UserNameViewSet(viewsets.ModelViewSet): @@ -180,6 +185,33 @@ class RecipeViewSet(viewsets.ModelViewSet): queryset = queryset[:int(limit)] return queryset + @decorators.action( + detail=True, + methods=['PUT'], + serializer_class=RecipeImageSerializer, + parser_classes=[MultiPartParser], + ) + def image(self, request, pk): + obj = self.get_object() + serializer = self.serializer_class(obj, data=request.data, partial=True) + + if serializer.is_valid(): + serializer.save() + img = Image.open(obj.image) + + basewidth = 720 + wpercent = (basewidth / float(img.size[0])) + hsize = int((float(img.size[1]) * float(wpercent))) + img = img.resize((basewidth, hsize), Image.ANTIALIAS) + + im_io = io.BytesIO() + img.save(im_io, 'PNG', quality=70) + obj.image = File(im_io, name=f'{uuid.uuid4()}_{obj.pk}.png') + obj.save() + + return Response(serializer.data) + return Response(serializer.errors, 400) + class KeywordViewSet(viewsets.ModelViewSet): """