lots of small fixes

This commit is contained in:
vabene1111
2022-04-22 19:26:49 +02:00
parent 42dfc9d126
commit 3cf0395a18
12 changed files with 153 additions and 1110 deletions

View File

@ -1,6 +1,3 @@
"""
Source: https://djangosnippets.org/snippets/1703/
"""
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test
@ -12,7 +9,7 @@ from django.utils.translation import gettext as _
from rest_framework import permissions
from rest_framework.permissions import SAFE_METHODS
from cookbook.models import ShareLink
from cookbook.models import ShareLink, Recipe, UserPreference
def get_allowed_groups(groups_required):
@ -262,3 +259,38 @@ class CustomIsShare(permissions.BasePermission):
if share:
return share_link_valid(obj, share)
return False
def above_space_limit(space): # TODO add file storage limit
"""
Test if the space has reached any limit (e.g. max recipes, users, ..)
:param space: Space to test for limits
:return: Tuple (True if above or equal any limit else false, message)
"""
r_limit, r_msg = above_space_recipe_limit(space)
u_limit, u_msg = above_space_user_limit(space)
return r_limit or u_limit, (r_msg + ' ' + u_msg).strip()
def above_space_recipe_limit(space):
"""
Test if a space has reached its recipe limit
:param space: Space to test for limits
:return: Tuple (True if above or equal limit else false, message)
"""
limit = space.max_recipes != 0 and Recipe.objects.filter(space=space).count() >= space.max_recipes
if limit:
return True, _('You have reached the maximum number of recipes for your space.')
return False, ''
def above_space_user_limit(space):
"""
Test if a space has reached its user limit
:param space: Space to test for limits
:return: Tuple (True if above or equal limit else false, message)
"""
limit = space.max_users != 0 and UserPreference.objects.filter(space=space).count() > space.max_users
if limit:
return True, _('You have more users than allowed in your space.')
return False, ''

View File

@ -113,6 +113,14 @@ def get_from_scraper(scrape, request):
keywords += listify_keywords(scrape.schema.data.get("recipeCuisine"))
except Exception:
pass
if source_url := scrape.canonical_url():
recipe_json['source_url'] = source_url
try:
keywords.append(source_url.replace('http://', '').replace('https://', '').split('/')[0])
except Exception:
pass
try:
recipe_json['keywords'] = parse_keywords(list(set(map(str.casefold, keywords))), request.space)
except AttributeError:
@ -136,19 +144,18 @@ def get_from_scraper(scrape, request):
for x in scrape.ingredients():
try:
amount, unit, ingredient, note = ingredient_parser.parse(x)
recipe_json['steps'][0]['ingredients'].append(
{
ingredient = {
'amount': amount,
'unit': {
'name': unit,
},
'food': {
'name': ingredient,
},
'unit': None,
'note': note,
'original_text': x
}
)
if unit:
ingredient['unit'] = {'name': unit, }
recipe_json['steps'][0]['ingredients'].append(ingredient)
except Exception:
recipe_json['steps'][0]['ingredients'].append(
{
@ -164,8 +171,6 @@ def get_from_scraper(scrape, request):
except Exception:
pass
if scrape.canonical_url():
recipe_json['source_url'] = scrape.canonical_url()
return recipe_json

View File

@ -12,6 +12,7 @@ from rest_framework.exceptions import NotFound, ValidationError
from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
from cookbook.helper.HelperFunctions import str2bool
from cookbook.helper.permission_helper import above_space_limit
from cookbook.helper.shopping_helper import RecipeShoppingEditor
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, CustomFilter,
ExportLog, Food, FoodInheritField, ImportLog, Ingredient, Keyword,
@ -649,6 +650,12 @@ class RecipeSerializer(RecipeBaseSerializer):
)
read_only_fields = ['image', 'created_by', 'created_at']
def validate(self, data):
above_limit, msg = above_space_limit(self.context['request'].space)
if above_limit:
raise serializers.ValidationError(msg)
return super().validate(data)
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].space
@ -971,12 +978,19 @@ class AutomationSerializer(serializers.ModelSerializer):
# CORS, REST and Scopes aren't currently working
# Scopes are evaluating before REST has authenticated the user assigning a None space
# I've made the change below to fix the bookmarklet, other serializers likely need a similar/better fix
class BookmarkletImportSerializer(serializers.ModelSerializer):
class BookmarkletImportListSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].user.userpreference.space
return super().create(validated_data)
class Meta:
model = BookmarkletImport
fields = ('id', 'url', 'created_by', 'created_at')
read_only_fields = ('created_by', 'space')
class BookmarkletImportSerializer(BookmarkletImportListSerializer):
class Meta:
model = BookmarkletImport
fields = ('id', 'url', 'html', 'created_by', 'created_at')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -70,7 +70,7 @@ from cookbook.serializer import (AutomationSerializer, BookmarkletImportSerializ
SupermarketCategorySerializer, SupermarketSerializer,
SyncLogSerializer, SyncSerializer, UnitSerializer,
UserFileSerializer, UserNameSerializer, UserPreferenceSerializer,
ViewLogSerializer, IngredientSimpleSerializer)
ViewLogSerializer, IngredientSimpleSerializer, BookmarkletImportListSerializer)
from recipes import settings
@ -974,6 +974,11 @@ class BookmarkletImportViewSet(viewsets.ModelViewSet):
serializer_class = BookmarkletImportSerializer
permission_classes = [CustomIsUser]
def get_serializer_class(self):
if self.action == 'list':
return BookmarkletImportListSerializer
return self.serializer_class
def get_queryset(self):
return self.queryset.filter(space=self.request.space).all()

View File

@ -10,7 +10,7 @@ from django_tables2 import RequestConfig
from rest_framework.authtoken.models import Token
from cookbook.forms import BatchEditForm, SyncForm
from cookbook.helper.permission_helper import group_required, has_group_permission
from cookbook.helper.permission_helper import group_required, has_group_permission, above_space_limit
from cookbook.models import (Comment, Food, Keyword, Recipe, RecipeImport, Sync,
Unit, UserPreference, BookmarkletImport)
from cookbook.tables import SyncTable
@ -19,12 +19,9 @@ from recipes import settings
@group_required('user')
def sync(request):
if request.space.max_recipes != 0 and Recipe.objects.filter(space=request.space).count() >= request.space.max_recipes: # TODO move to central helper function
messages.add_message(request, messages.WARNING, _('You have reached the maximum number of recipes for your space.'))
return HttpResponseRedirect(reverse('index'))
if request.space.max_users != 0 and UserPreference.objects.filter(space=request.space).count() > request.space.max_users:
messages.add_message(request, messages.WARNING, _('You have more users than allowed in your space.'))
limit, msg = above_space_limit(request.space)
if limit:
messages.add_message(request, messages.WARNING, msg)
return HttpResponseRedirect(reverse('index'))
if request.space.demo or settings.HOSTED:
@ -113,12 +110,9 @@ def batch_edit(request):
@group_required('user')
def import_url(request):
if request.space.max_recipes != 0 and Recipe.objects.filter(space=request.space).count() >= request.space.max_recipes: # TODO move to central helper function
messages.add_message(request, messages.WARNING, _('You have reached the maximum number of recipes for your space.'))
return HttpResponseRedirect(reverse('index'))
if request.space.max_users != 0 and UserPreference.objects.filter(space=request.space).count() > request.space.max_users:
messages.add_message(request, messages.WARNING, _('You have more users than allowed in your space.'))
limit, msg = above_space_limit(request.space)
if limit:
messages.add_message(request, messages.WARNING, msg)
return HttpResponseRedirect(reverse('index'))
if (api_token := Token.objects.filter(user=request.user).first()) is None:
@ -129,7 +123,7 @@ def import_url(request):
if bookmarklet_import := BookmarkletImport.objects.filter(id=request.GET['id']).first():
bookmarklet_import_id = bookmarklet_import.pk
return render(request, 'test.html', {'api_token': api_token, 'bookmarklet_import_id': bookmarklet_import_id})
return render(request, 'url_import.html', {'api_token': api_token, 'bookmarklet_import_id': bookmarklet_import_id})
class Object(object):

View File

@ -9,7 +9,7 @@ from django.views.generic import UpdateView
from django.views.generic.edit import FormMixin
from cookbook.forms import CommentForm, ExternalRecipeForm, MealPlanForm, StorageForm, SyncForm
from cookbook.helper.permission_helper import GroupRequiredMixin, OwnerRequiredMixin, group_required
from cookbook.helper.permission_helper import GroupRequiredMixin, OwnerRequiredMixin, group_required, above_space_limit
from cookbook.models import (Comment, MealPlan, MealType, Recipe, RecipeImport, Storage, Sync,
UserPreference)
from cookbook.provider.dropbox import Dropbox
@ -39,12 +39,9 @@ def convert_recipe(request, pk):
@group_required('user')
def internal_recipe_update(request, pk):
if request.space.max_recipes != 0 and Recipe.objects.filter(space=request.space).count() > request.space.max_recipes: # TODO move to central helper function
messages.add_message(request, messages.WARNING, _('You have reached the maximum number of recipes for your space.'))
return HttpResponseRedirect(reverse('view_recipe', args=[pk]))
if request.space.max_users != 0 and UserPreference.objects.filter(space=request.space).count() > request.space.max_users:
messages.add_message(request, messages.WARNING, _('You have more users than allowed in your space.'))
limit, msg = above_space_limit(request.space)
if limit:
messages.add_message(request, messages.WARNING, msg)
return HttpResponseRedirect(reverse('view_recipe', args=[pk]))
recipe_instance = get_object_or_404(Recipe, pk=pk, space=request.space)

View File

@ -10,7 +10,7 @@ from django.urls import reverse
from django.utils.translation import gettext as _
from cookbook.forms import ExportForm, ImportExportBase, ImportForm
from cookbook.helper.permission_helper import group_required
from cookbook.helper.permission_helper import group_required, above_space_limit
from cookbook.helper.recipe_search import RecipeSearch
from cookbook.integration.cheftap import ChefTap
from cookbook.integration.chowdown import Chowdown
@ -84,12 +84,9 @@ def get_integration(request, export_type):
@group_required('user')
def import_recipe(request):
if request.space.max_recipes != 0 and Recipe.objects.filter(space=request.space).count() >= request.space.max_recipes: # TODO move to central helper function
messages.add_message(request, messages.WARNING, _('You have reached the maximum number of recipes for your space.'))
return HttpResponseRedirect(reverse('index'))
if request.space.max_users != 0 and UserPreference.objects.filter(space=request.space).count() > request.space.max_users:
messages.add_message(request, messages.WARNING, _('You have more users than allowed in your space.'))
limit, msg = above_space_limit(request.space)
if limit:
messages.add_message(request, messages.WARNING, msg)
return HttpResponseRedirect(reverse('index'))
if request.method == "POST":

View File

@ -106,10 +106,12 @@
<div class="row">
<div class="col-12 col-md-8 offset-0 offset-md-2">
<h4 class="text-center flex-grow-1" v-b-tooltip.hover.bottom :title="$t('Click_To_Edit')" v-if="!edit_name"
<h4 class="text-center flex-grow-1" v-b-tooltip.hover.bottom
:title="$t('Click_To_Edit')" v-if="!edit_name"
@click="edit_name = true">{{
recipe_json.name
}} <span class="text-primary"><i class="fa fa-edit"></i> </span> </h4>
}} <span class="text-primary"><i class="fa fa-edit"></i> </span>
</h4>
<b-input-group v-if="edit_name" class="mb-2">
<b-input
class="form-control form-control-borderless form-control-search"
@ -235,6 +237,11 @@
{{ $t('import_duplicates') }}
</b-form-checkbox>
<a href="recipe_app_info.help_url"
v-if="recipe_app_info !== undefined && recipe_app_info.help_url !== ''">{{
$t('Help')
}}</a>
<b-form-file
class="my-2"
multiple
@ -312,6 +319,11 @@ export default {
RecipeCard,
ImportViewStepEditor
},
computed: {
recipe_app_info: function () {
return this.INTEGRATIONS.filter(x => x.id === this.recipe_app)[0]
},
},
data() {
return {
tab_index: 0,
@ -343,7 +355,8 @@ export default {
recipe_files: [],
loading: false,
empty_input: false,
edit_name: false,// Bookmarklet
edit_name: false,
// Bookmarklet
BOOKMARKLET_CODE: window.BOOKMARKLET_CODE
}
},
@ -422,7 +435,7 @@ export default {
window.localStorage.setItem(this.LS_IMPORT_RECENT, JSON.stringify(this.recent_urls))
}
if (this.website_url === '') {
if (this.website_url === '' && bookmarklet === undefined) {
this.empty_input = true
setTimeout(() => {
this.empty_input = false
@ -541,7 +554,7 @@ export default {
`localStorage.setItem("token", "${window.API_TOKEN}");` +
`document.body.appendChild(document.createElement("script")).src="${localStorage.getItem('BASE_PATH')}${resolveDjangoStatic('/js/bookmarklet.js')}?r="+Math.floor(Math.random()*999999999)}` +
`})()`
}
},
},
directives: {
hover: {

View File

@ -1,24 +1,24 @@
// containing all data and functions regarding the different integrations
export const INTEGRATIONS = [
{id: 'DEFAULT', name: "Tandoor", import: true, export: true},
{id: 'CHEFTAP', name: "Cheftap", import: true, export: false},
{id: 'CHOWDOWN', name: "Chowdown", import: true, export: false},
{id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false},
{id: 'COOKMATE', name: "Cookmate", import: true, export: false},
{id: 'COPYMETHAT', name: "CopyMeThat", import: true, export: false},
{id: 'DOMESTICA', name: "Domestica", import: true, export: false},
{id: 'MEALIE', name: "Mealie", import: true, export: false},
{id: 'MEALMASTER', name: "Mealmaster", import: true, export: false},
{id: 'MELARECIPES', name: "Melarecipes", import: true, export: false},
{id: 'NEXTCLOUD', name: "Nextcloud Cookbook", import: true, export: false},
{id: 'OPENEATS', name: "Openeats", import: true, export: false},
{id: 'PAPRIKA', name: "Paprika", import: true, export: false},
{id: 'PEPPERPLATE', name: "Pepperplate", import: true, export: false},
{id: 'PLANTOEAT', name: "Plantoeat", import: true, export: false},
{id: 'RECETTETEK', name: "RecetteTek", import: true, export: false},
{id: 'RECIPEKEEPER', name: "Recipekeeper", import: true, export: false},
{id: 'RECIPESAGE', name: "Recipesage", import: true, export: true},
{id: 'REZKONV', name: "Rezkonv", import: true, export: false},
{id: 'SAFRON', name: "Safron", import: true, export: true},
{id: 'DEFAULT', name: "Tandoor", import: true, export: true, help_url: 'https://docs.tandoor.dev/features/import_export/#default'},
{id: 'CHEFTAP', name: "Cheftap", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#cheftap'},
{id: 'CHOWDOWN', name: "Chowdown", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#chowdown'},
{id: 'COOKBOOKAPP', name: "CookBookApp", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#cookbookapp'},
{id: 'COOKMATE', name: "Cookmate", import: true, export: false, help_url: ''},
{id: 'COPYMETHAT', name: "CopyMeThat", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#copymethat'},
{id: 'DOMESTICA', name: "Domestica", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#domestica'},
{id: 'MEALIE', name: "Mealie", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#mealie'},
{id: 'MEALMASTER', name: "Mealmaster", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#mealmaster'},
{id: 'MELARECIPES', name: "Melarecipes", import: true, export: false, help_url: ''},
{id: 'NEXTCLOUD', name: "Nextcloud Cookbook", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#nextcloud'},
{id: 'OPENEATS', name: "Openeats", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#openeats'},
{id: 'PAPRIKA', name: "Paprika", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#paprika'},
{id: 'PEPPERPLATE', name: "Pepperplate", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#pepperplate'},
{id: 'PLANTOEAT', name: "Plantoeat", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#plantoeat'},
{id: 'RECETTETEK', name: "RecetteTek", import: true, export: false, help_url: ''},
{id: 'RECIPEKEEPER', name: "Recipekeeper", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#recipekeeper'},
{id: 'RECIPESAGE', name: "Recipesage", import: true, export: true, help_url: 'https://docs.tandoor.dev/features/import_export/#recipesage'},
{id: 'REZKONV', name: "Rezkonv", import: true, export: false, help_url: 'https://docs.tandoor.dev/features/import_export/#rezkonv'},
{id: 'SAFRON', name: "Safron", import: true, export: true, help_url: 'https://docs.tandoor.dev/features/import_export/#safron'},
]