Merge branch 'TandoorRecipes:develop' into develop
This commit is contained in:
commit
c020bea41e
@ -68,6 +68,10 @@ SHOPPING_MIN_AUTOSYNC_INTERVAL=5
|
||||
# when unset: 1 (true) - this is temporary until an appropriate amount of time has passed for everyone to migrate
|
||||
GUNICORN_MEDIA=0
|
||||
|
||||
# GUNICORN SERVER RELATED SETTINGS (see https://docs.gunicorn.org/en/stable/design.html#how-many-workers for recommended settings)
|
||||
# GUNICORN_WORKERS=1
|
||||
# GUNICORN_THREADS=1
|
||||
|
||||
# S3 Media settings: store mediafiles in s3 or any compatible storage backend (e.g. minio)
|
||||
# as long as S3_ACCESS_KEY is not set S3 features are disabled
|
||||
# S3_ACCESS_KEY=
|
||||
@ -77,6 +81,7 @@ GUNICORN_MEDIA=0
|
||||
# S3_QUERYSTRING_AUTH=1 # default true, set to 0 to serve media from a public bucket without signed urls
|
||||
# S3_QUERYSTRING_EXPIRE=3600 # number of seconds querystring are valid for
|
||||
# S3_ENDPOINT_URL= # when using a custom endpoint like minio
|
||||
# S3_CUSTOM_DOMAIN= # when using a CDN/proxy to S3 (see https://github.com/TandoorRecipes/recipes/issues/1943)
|
||||
|
||||
# Email Settings, see https://docs.djangoproject.com/en/3.2/ref/settings/#email-host
|
||||
# Required for email confirmation and password reset (automatically activates if host is set)
|
||||
|
4
boot.sh
4
boot.sh
@ -2,6 +2,8 @@
|
||||
source venv/bin/activate
|
||||
|
||||
TANDOOR_PORT="${TANDOOR_PORT:-8080}"
|
||||
GUNICORN_WORKERS="${GUNICORN_WORKERS}"
|
||||
GUNICORN_THREADS="${GUNICORN_THREADS}"
|
||||
NGINX_CONF_FILE=/opt/recipes/nginx/conf.d/Recipes.conf
|
||||
|
||||
display_warning() {
|
||||
@ -63,4 +65,4 @@ echo "Done"
|
||||
|
||||
chmod -R 755 /opt/recipes/mediafiles
|
||||
|
||||
exec gunicorn -b :$TANDOOR_PORT --access-logfile - --error-logfile - --log-level INFO recipes.wsgi
|
||||
exec gunicorn -b :$TANDOOR_PORT --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level INFO recipes.wsgi
|
||||
|
@ -15,7 +15,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField
|
||||
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
|
||||
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
|
||||
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation)
|
||||
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace)
|
||||
|
||||
|
||||
class CustomUserAdmin(UserAdmin):
|
||||
@ -46,15 +46,23 @@ class SpaceAdmin(admin.ModelAdmin):
|
||||
admin.site.register(Space, SpaceAdmin)
|
||||
|
||||
|
||||
class UserSpaceAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'space',)
|
||||
search_fields = ('user', 'space',)
|
||||
|
||||
|
||||
admin.site.register(UserSpace, UserSpaceAdmin)
|
||||
|
||||
|
||||
class UserPreferenceAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'theme', 'nav_color', 'default_page', 'search_style',) # TODO add new fields
|
||||
list_display = ('name', 'theme', 'nav_color', 'default_page',)
|
||||
search_fields = ('user__username',)
|
||||
list_filter = ('theme', 'nav_color', 'default_page', 'search_style')
|
||||
list_filter = ('theme', 'nav_color', 'default_page',)
|
||||
date_hierarchy = 'created_at'
|
||||
|
||||
@staticmethod
|
||||
def name(obj):
|
||||
return obj.user.get_user_name()
|
||||
return obj.user.get_user_display_name()
|
||||
|
||||
|
||||
admin.site.register(UserPreference, UserPreferenceAdmin)
|
||||
@ -67,7 +75,7 @@ class SearchPreferenceAdmin(admin.ModelAdmin):
|
||||
|
||||
@staticmethod
|
||||
def name(obj):
|
||||
return obj.user.get_user_name()
|
||||
return obj.user.get_user_display_name()
|
||||
|
||||
|
||||
admin.site.register(SearchPreference, SearchPreferenceAdmin)
|
||||
@ -169,7 +177,7 @@ class RecipeAdmin(admin.ModelAdmin):
|
||||
|
||||
@staticmethod
|
||||
def created_by(obj):
|
||||
return obj.created_by.get_user_name()
|
||||
return obj.created_by.get_user_display_name()
|
||||
|
||||
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2', 'django.db.backends.postgresql']:
|
||||
actions = [rebuild_index]
|
||||
@ -208,7 +216,7 @@ class CommentAdmin(admin.ModelAdmin):
|
||||
|
||||
@staticmethod
|
||||
def name(obj):
|
||||
return obj.created_by.get_user_name()
|
||||
return obj.created_by.get_user_display_name()
|
||||
|
||||
|
||||
admin.site.register(Comment, CommentAdmin)
|
||||
@ -227,7 +235,7 @@ class RecipeBookAdmin(admin.ModelAdmin):
|
||||
|
||||
@staticmethod
|
||||
def user_name(obj):
|
||||
return obj.created_by.get_user_name()
|
||||
return obj.created_by.get_user_display_name()
|
||||
|
||||
|
||||
admin.site.register(RecipeBook, RecipeBookAdmin)
|
||||
@ -245,7 +253,7 @@ class MealPlanAdmin(admin.ModelAdmin):
|
||||
|
||||
@staticmethod
|
||||
def user(obj):
|
||||
return obj.created_by.get_user_name()
|
||||
return obj.created_by.get_user_display_name()
|
||||
|
||||
|
||||
admin.site.register(MealPlan, MealPlanAdmin)
|
||||
|
@ -1,62 +0,0 @@
|
||||
import django_filters
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.forms import MultiSelectWidget
|
||||
from cookbook.models import Food, Keyword, Recipe
|
||||
|
||||
with scopes_disabled():
|
||||
class RecipeFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(method='filter_name')
|
||||
keywords = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Keyword.objects.none(),
|
||||
widget=MultiSelectWidget,
|
||||
method='filter_keywords'
|
||||
)
|
||||
foods = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=Food.objects.none(),
|
||||
widget=MultiSelectWidget,
|
||||
method='filter_foods',
|
||||
label=_('Ingredients')
|
||||
)
|
||||
|
||||
def __init__(self, data=None, *args, **kwargs):
|
||||
space = kwargs.pop('space')
|
||||
super().__init__(data, *args, **kwargs)
|
||||
self.filters['foods'].queryset = Food.objects.filter(space=space).all()
|
||||
self.filters['keywords'].queryset = Keyword.objects.filter(space=space).all()
|
||||
|
||||
@staticmethod
|
||||
def filter_keywords(queryset, name, value):
|
||||
if not name == 'keywords':
|
||||
return queryset
|
||||
for x in value:
|
||||
queryset = queryset.filter(keywords=x)
|
||||
return queryset
|
||||
|
||||
@staticmethod
|
||||
def filter_foods(queryset, name, value):
|
||||
if not name == 'foods':
|
||||
return queryset
|
||||
for x in value:
|
||||
queryset = queryset.filter(steps__ingredients__food__name=x).distinct()
|
||||
return queryset
|
||||
|
||||
@staticmethod
|
||||
def filter_name(queryset, name, value):
|
||||
if not name == 'name':
|
||||
return queryset
|
||||
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
||||
'django.db.backends.postgresql']:
|
||||
queryset = queryset.annotate(similarity=TrigramSimilarity('name', value), ).filter(
|
||||
Q(similarity__gt=0.1) | Q(name__unaccent__icontains=value)).order_by('-similarity')
|
||||
else:
|
||||
queryset = queryset.filter(name__icontains=value)
|
||||
return queryset
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
fields = ['name', 'keywords', 'foods', 'internal']
|
@ -45,8 +45,7 @@ class UserPreferenceForm(forms.ModelForm):
|
||||
model = UserPreference
|
||||
fields = (
|
||||
'default_unit', 'use_fractions', 'use_kj', 'theme', 'nav_color',
|
||||
'sticky_navbar', 'default_page', 'show_recent', 'search_style',
|
||||
'plan_share', 'ingredient_decimals', 'comments', 'left_handed',
|
||||
'sticky_navbar', 'default_page', 'plan_share', 'ingredient_decimals', 'comments', 'left_handed',
|
||||
)
|
||||
|
||||
labels = {
|
||||
@ -57,8 +56,6 @@ class UserPreferenceForm(forms.ModelForm):
|
||||
'nav_color': _('Navbar color'),
|
||||
'sticky_navbar': _('Sticky navbar'),
|
||||
'default_page': _('Default page'),
|
||||
'show_recent': _('Show recent recipes'),
|
||||
'search_style': _('Search style'),
|
||||
'plan_share': _('Plan sharing'),
|
||||
'ingredient_decimals': _('Ingredient decimal places'),
|
||||
'shopping_auto_sync': _('Shopping list auto sync period'),
|
||||
@ -68,23 +65,21 @@ class UserPreferenceForm(forms.ModelForm):
|
||||
|
||||
help_texts = {
|
||||
'nav_color': _('Color of the top navigation bar. Not all colors work with all themes, just try them out!'),
|
||||
# noqa: E501
|
||||
'default_unit': _('Default Unit to be used when inserting a new ingredient into a recipe.'), # noqa: E501
|
||||
|
||||
'default_unit': _('Default Unit to be used when inserting a new ingredient into a recipe.'),
|
||||
'use_fractions': _(
|
||||
'Enables support for fractions in ingredient amounts (e.g. convert decimals to fractions automatically)'),
|
||||
# noqa: E501
|
||||
'use_kj': _('Display nutritional energy amounts in joules instead of calories'), # noqa: E501
|
||||
|
||||
'use_kj': _('Display nutritional energy amounts in joules instead of calories'),
|
||||
'plan_share': _('Users with whom newly created meal plans should be shared by default.'),
|
||||
'shopping_share': _('Users with whom to share shopping lists.'),
|
||||
# noqa: E501
|
||||
'show_recent': _('Show recently viewed recipes on search page.'), # noqa: E501
|
||||
'ingredient_decimals': _('Number of decimals to round ingredients.'), # noqa: E501
|
||||
'comments': _('If you want to be able to create and see comments underneath recipes.'), # noqa: E501
|
||||
'ingredient_decimals': _('Number of decimals to round ingredients.'),
|
||||
'comments': _('If you want to be able to create and see comments underneath recipes.'),
|
||||
'shopping_auto_sync': _(
|
||||
'Setting to 0 will disable auto sync. When viewing a shopping list the list is updated every set seconds to sync changes someone else might have made. Useful when shopping with multiple people but might use a little bit ' # noqa: E501
|
||||
'of mobile data. If lower than instance limit it is reset when saving.' # noqa: E501
|
||||
'Setting to 0 will disable auto sync. When viewing a shopping list the list is updated every set seconds to sync changes someone else might have made. Useful when shopping with multiple people but might use a little bit '
|
||||
'of mobile data. If lower than instance limit it is reset when saving.'
|
||||
),
|
||||
'sticky_navbar': _('Makes the navbar stick to the top of the page.'), # noqa: E501
|
||||
'sticky_navbar': _('Makes the navbar stick to the top of the page.'),
|
||||
'mealplan_autoadd_shopping': _('Automatically add meal plan ingredients to shopping list.'),
|
||||
'mealplan_autoexclude_onhand': _('Exclude ingredients that are on hand.'),
|
||||
'left_handed': _('Will optimize the UI for use with your left hand.')
|
||||
@ -336,9 +331,9 @@ class MealPlanForm(forms.ModelForm):
|
||||
)
|
||||
|
||||
help_texts = {
|
||||
'shared': _('You can list default users to share recipes with in the settings.'), # noqa: E501
|
||||
'shared': _('You can list default users to share recipes with in the settings.'),
|
||||
'note': _('You can use markdown to format this field. See the <a href="/docs/markdown/">docs here</a>')
|
||||
# noqa: E501
|
||||
|
||||
}
|
||||
|
||||
widgets = {
|
||||
@ -493,8 +488,8 @@ class ShoppingPreferenceForm(forms.ModelForm):
|
||||
help_texts = {
|
||||
'shopping_share': _('Users will see all items you add to your shopping list. They must add you to see items on their list.'),
|
||||
'shopping_auto_sync': _(
|
||||
'Setting to 0 will disable auto sync. When viewing a shopping list the list is updated every set seconds to sync changes someone else might have made. Useful when shopping with multiple people but might use a little bit ' # noqa: E501
|
||||
'of mobile data. If lower than instance limit it is reset when saving.' # noqa: E501
|
||||
'Setting to 0 will disable auto sync. When viewing a shopping list the list is updated every set seconds to sync changes someone else might have made. Useful when shopping with multiple people but might use a little bit '
|
||||
'of mobile data. If lower than instance limit it is reset when saving.'
|
||||
),
|
||||
'mealplan_autoadd_shopping': _('Automatically add meal plan ingredients to shopping list.'),
|
||||
'mealplan_autoinclude_related': _('When adding a meal plan to the shopping list (manually or automatically), include all related recipes.'),
|
||||
|
@ -14,7 +14,7 @@ class AllAuthCustomAdapter(DefaultAccountAdapter):
|
||||
|
||||
def is_open_for_signup(self, request):
|
||||
"""
|
||||
Whether to allow sign ups.
|
||||
Whether to allow sign-ups.
|
||||
"""
|
||||
signup_token = False
|
||||
if 'signup_token' in request.session and InviteLink.objects.filter(valid_until__gte=datetime.datetime.today(), used_by=None, uuid=request.session['signup_token']).exists():
|
||||
@ -31,7 +31,10 @@ class AllAuthCustomAdapter(DefaultAccountAdapter):
|
||||
default = datetime.datetime.now()
|
||||
c = caches['default'].get_or_set(email, default, timeout=360)
|
||||
if c == default:
|
||||
super(AllAuthCustomAdapter, self).send_mail(template_prefix, email, context)
|
||||
try:
|
||||
super(AllAuthCustomAdapter, self).send_mail(template_prefix, email, context)
|
||||
except Exception: # dont fail signup just because confirmation mail could not be send
|
||||
pass
|
||||
else:
|
||||
messages.add_message(self.request, messages.ERROR, _('In order to prevent spam, the requested email was not send. Please wait a few minutes and try again.'))
|
||||
else:
|
||||
|
@ -10,4 +10,5 @@ def context_settings(request):
|
||||
'TERMS_URL': settings.TERMS_URL,
|
||||
'PRIVACY_URL': settings.PRIVACY_URL,
|
||||
'IMPRINT_URL': settings.IMPRINT_URL,
|
||||
'SHOPPING_MIN_AUTOSYNC_INTERVAL': settings.SHOPPING_MIN_AUTOSYNC_INTERVAL,
|
||||
}
|
||||
|
@ -6,10 +6,12 @@ from django.core.exceptions import ValidationError, ObjectDoesNotExist
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from oauth2_provider.contrib.rest_framework import TokenHasScope, TokenHasReadWriteScope
|
||||
from oauth2_provider.models import AccessToken
|
||||
from rest_framework import permissions
|
||||
from rest_framework.permissions import SAFE_METHODS
|
||||
|
||||
from cookbook.models import ShareLink, Recipe, UserPreference, UserSpace
|
||||
from cookbook.models import ShareLink, Recipe, UserSpace
|
||||
|
||||
|
||||
def get_allowed_groups(groups_required):
|
||||
@ -299,6 +301,73 @@ class CustomIsShare(permissions.BasePermission):
|
||||
return False
|
||||
|
||||
|
||||
class CustomRecipePermission(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission class for recipe api endpoint
|
||||
"""
|
||||
message = _('You do not have the required permissions to view this page!')
|
||||
|
||||
def has_permission(self, request, view): # user is either at least a guest or a share link is given and the request is safe
|
||||
share = request.query_params.get('share', None)
|
||||
return has_group_permission(request.user, ['guest']) or (share and request.method in SAFE_METHODS and 'pk' in view.kwargs)
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
share = request.query_params.get('share', None)
|
||||
if share:
|
||||
return share_link_valid(obj, share)
|
||||
else:
|
||||
if obj.private:
|
||||
return ((obj.created_by == request.user) or (request.user in obj.shared.all())) and obj.space == request.space
|
||||
else:
|
||||
return has_group_permission(request.user, ['guest']) and obj.space == request.space
|
||||
|
||||
|
||||
class CustomUserPermission(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission class for user api endpoint
|
||||
"""
|
||||
message = _('You do not have the required permissions to view this page!')
|
||||
|
||||
def has_permission(self, request, view): # a space filtered user list is visible for everyone
|
||||
return has_group_permission(request.user, ['guest'])
|
||||
|
||||
def has_object_permission(self, request, view, obj): # object write permissions are only available for user
|
||||
if request.method in SAFE_METHODS and 'pk' in view.kwargs and has_group_permission(request.user, ['guest']) and request.space in obj.userspace_set.all():
|
||||
return True
|
||||
elif request.user == obj:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class CustomTokenHasScope(TokenHasScope):
|
||||
"""
|
||||
Custom implementation of Django OAuth Toolkit TokenHasScope class
|
||||
Only difference: if any other authentication method except OAuth2Authentication is used the scope check is ignored
|
||||
IMPORTANT: do not use this class without any other permission class as it will not check anything besides token scopes
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if type(request.auth) == AccessToken:
|
||||
return super().has_permission(request, view)
|
||||
else:
|
||||
return request.user.is_authenticated
|
||||
|
||||
|
||||
class CustomTokenHasReadWriteScope(TokenHasReadWriteScope):
|
||||
"""
|
||||
Custom implementation of Django OAuth Toolkit TokenHasReadWriteScope class
|
||||
Only difference: if any other authentication method except OAuth2Authentication is used the scope check is ignored
|
||||
IMPORTANT: do not use this class without any other permission class as it will not check anything besides token scopes
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if type(request.auth) == AccessToken:
|
||||
return super().has_permission(request, view)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def above_space_limit(space): # TODO add file storage limit
|
||||
"""
|
||||
Test if the space has reached any limit (e.g. max recipes, users, ..)
|
||||
|
@ -1,189 +1,191 @@
|
||||
import json
|
||||
import re
|
||||
from json import JSONDecodeError
|
||||
from urllib.parse import unquote
|
||||
# import json
|
||||
# import re
|
||||
# from json import JSONDecodeError
|
||||
# from urllib.parse import unquote
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4.element import Tag
|
||||
from recipe_scrapers import scrape_html, scrape_me
|
||||
from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
|
||||
from recipe_scrapers._utils import get_host_name, normalize_string
|
||||
# from bs4 import BeautifulSoup
|
||||
# from bs4.element import Tag
|
||||
# from recipe_scrapers import scrape_html, scrape_me
|
||||
# from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
|
||||
# from recipe_scrapers._utils import get_host_name, normalize_string
|
||||
|
||||
from cookbook.helper import recipe_url_import as helper
|
||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
# from cookbook.helper import recipe_url_import as helper
|
||||
# from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
|
||||
|
||||
def get_recipe_from_source(text, url, request):
|
||||
def build_node(k, v):
|
||||
if isinstance(v, dict):
|
||||
node = {
|
||||
'name': k,
|
||||
'value': k,
|
||||
'children': get_children_dict(v)
|
||||
}
|
||||
elif isinstance(v, list):
|
||||
node = {
|
||||
'name': k,
|
||||
'value': k,
|
||||
'children': get_children_list(v)
|
||||
}
|
||||
else:
|
||||
node = {
|
||||
'name': k + ": " + normalize_string(str(v)),
|
||||
'value': normalize_string(str(v))
|
||||
}
|
||||
return node
|
||||
# def get_recipe_from_source(text, url, request):
|
||||
# def build_node(k, v):
|
||||
# if isinstance(v, dict):
|
||||
# node = {
|
||||
# 'name': k,
|
||||
# 'value': k,
|
||||
# 'children': get_children_dict(v)
|
||||
# }
|
||||
# elif isinstance(v, list):
|
||||
# node = {
|
||||
# 'name': k,
|
||||
# 'value': k,
|
||||
# 'children': get_children_list(v)
|
||||
# }
|
||||
# else:
|
||||
# node = {
|
||||
# 'name': k + ": " + normalize_string(str(v)),
|
||||
# 'value': normalize_string(str(v))
|
||||
# }
|
||||
# return node
|
||||
|
||||
def get_children_dict(children):
|
||||
kid_list = []
|
||||
for k, v in children.items():
|
||||
kid_list.append(build_node(k, v))
|
||||
return kid_list
|
||||
# def get_children_dict(children):
|
||||
# kid_list = []
|
||||
# for k, v in children.items():
|
||||
# kid_list.append(build_node(k, v))
|
||||
# return kid_list
|
||||
|
||||
def get_children_list(children):
|
||||
kid_list = []
|
||||
for kid in children:
|
||||
if type(kid) == list:
|
||||
node = {
|
||||
'name': "unknown list",
|
||||
'value': "unknown list",
|
||||
'children': get_children_list(kid)
|
||||
}
|
||||
kid_list.append(node)
|
||||
elif type(kid) == dict:
|
||||
for k, v in kid.items():
|
||||
kid_list.append(build_node(k, v))
|
||||
else:
|
||||
kid_list.append({
|
||||
'name': normalize_string(str(kid)),
|
||||
'value': normalize_string(str(kid))
|
||||
})
|
||||
return kid_list
|
||||
# def get_children_list(children):
|
||||
# kid_list = []
|
||||
# for kid in children:
|
||||
# if type(kid) == list:
|
||||
# node = {
|
||||
# 'name': "unknown list",
|
||||
# 'value': "unknown list",
|
||||
# 'children': get_children_list(kid)
|
||||
# }
|
||||
# kid_list.append(node)
|
||||
# elif type(kid) == dict:
|
||||
# for k, v in kid.items():
|
||||
# kid_list.append(build_node(k, v))
|
||||
# else:
|
||||
# kid_list.append({
|
||||
# 'name': normalize_string(str(kid)),
|
||||
# 'value': normalize_string(str(kid))
|
||||
# })
|
||||
# return kid_list
|
||||
|
||||
recipe_tree = []
|
||||
parse_list = []
|
||||
soup = BeautifulSoup(text, "html.parser")
|
||||
html_data = get_from_html(soup)
|
||||
images = get_images_from_source(soup, url)
|
||||
text = unquote(text)
|
||||
scrape = None
|
||||
# recipe_tree = []
|
||||
# parse_list = []
|
||||
# soup = BeautifulSoup(text, "html.parser")
|
||||
# html_data = get_from_html(soup)
|
||||
# images = get_images_from_source(soup, url)
|
||||
# text = unquote(text)
|
||||
# scrape = None
|
||||
|
||||
if url:
|
||||
try:
|
||||
scrape = scrape_me(url_path=url, wild_mode=True)
|
||||
except(NoSchemaFoundInWildMode):
|
||||
pass
|
||||
if not scrape:
|
||||
try:
|
||||
parse_list.append(remove_graph(json.loads(text)))
|
||||
if not url and 'url' in parse_list[0]:
|
||||
url = parse_list[0]['url']
|
||||
scrape = text_scraper("<script type='application/ld+json'>" + text + "</script>", url=url)
|
||||
# if url and not text:
|
||||
# try:
|
||||
# scrape = scrape_me(url_path=url, wild_mode=True)
|
||||
# except(NoSchemaFoundInWildMode):
|
||||
# pass
|
||||
|
||||
except JSONDecodeError:
|
||||
for el in soup.find_all('script', type='application/ld+json'):
|
||||
el = remove_graph(el)
|
||||
if not url and 'url' in el:
|
||||
url = el['url']
|
||||
if type(el) == list:
|
||||
for le in el:
|
||||
parse_list.append(le)
|
||||
elif type(el) == dict:
|
||||
parse_list.append(el)
|
||||
for el in soup.find_all(type='application/json'):
|
||||
el = remove_graph(el)
|
||||
if type(el) == list:
|
||||
for le in el:
|
||||
parse_list.append(le)
|
||||
elif type(el) == dict:
|
||||
parse_list.append(el)
|
||||
scrape = text_scraper(text, url=url)
|
||||
# if not scrape:
|
||||
# try:
|
||||
# parse_list.append(remove_graph(json.loads(text)))
|
||||
# if not url and 'url' in parse_list[0]:
|
||||
# url = parse_list[0]['url']
|
||||
# scrape = text_scraper("<script type='application/ld+json'>" + text + "</script>", url=url)
|
||||
|
||||
recipe_json = helper.get_from_scraper(scrape, request)
|
||||
# except JSONDecodeError:
|
||||
# for el in soup.find_all('script', type='application/ld+json'):
|
||||
# el = remove_graph(el)
|
||||
# if not url and 'url' in el:
|
||||
# url = el['url']
|
||||
# if type(el) == list:
|
||||
# for le in el:
|
||||
# parse_list.append(le)
|
||||
# elif type(el) == dict:
|
||||
# parse_list.append(el)
|
||||
# for el in soup.find_all(type='application/json'):
|
||||
# el = remove_graph(el)
|
||||
# if type(el) == list:
|
||||
# for le in el:
|
||||
# parse_list.append(le)
|
||||
# elif type(el) == dict:
|
||||
# parse_list.append(el)
|
||||
# scrape = text_scraper(text, url=url)
|
||||
|
||||
for el in parse_list:
|
||||
temp_tree = []
|
||||
if isinstance(el, Tag):
|
||||
try:
|
||||
el = json.loads(el.string)
|
||||
except TypeError:
|
||||
continue
|
||||
# recipe_json = helper.get_from_scraper(scrape, request)
|
||||
|
||||
for k, v in el.items():
|
||||
if isinstance(v, dict):
|
||||
node = {
|
||||
'name': k,
|
||||
'value': k,
|
||||
'children': get_children_dict(v)
|
||||
}
|
||||
elif isinstance(v, list):
|
||||
node = {
|
||||
'name': k,
|
||||
'value': k,
|
||||
'children': get_children_list(v)
|
||||
}
|
||||
else:
|
||||
node = {
|
||||
'name': k + ": " + normalize_string(str(v)),
|
||||
'value': normalize_string(str(v))
|
||||
}
|
||||
temp_tree.append(node)
|
||||
# # TODO: DEPRECATE recipe_tree & html_data. first validate it isn't used anywhere
|
||||
# for el in parse_list:
|
||||
# temp_tree = []
|
||||
# if isinstance(el, Tag):
|
||||
# try:
|
||||
# el = json.loads(el.string)
|
||||
# except TypeError:
|
||||
# continue
|
||||
|
||||
if '@type' in el and el['@type'] == 'Recipe':
|
||||
recipe_tree += [{'name': 'ld+json', 'children': temp_tree}]
|
||||
else:
|
||||
recipe_tree += [{'name': 'json', 'children': temp_tree}]
|
||||
# for k, v in el.items():
|
||||
# if isinstance(v, dict):
|
||||
# node = {
|
||||
# 'name': k,
|
||||
# 'value': k,
|
||||
# 'children': get_children_dict(v)
|
||||
# }
|
||||
# elif isinstance(v, list):
|
||||
# node = {
|
||||
# 'name': k,
|
||||
# 'value': k,
|
||||
# 'children': get_children_list(v)
|
||||
# }
|
||||
# else:
|
||||
# node = {
|
||||
# 'name': k + ": " + normalize_string(str(v)),
|
||||
# 'value': normalize_string(str(v))
|
||||
# }
|
||||
# temp_tree.append(node)
|
||||
|
||||
return recipe_json, recipe_tree, html_data, images
|
||||
# if '@type' in el and el['@type'] == 'Recipe':
|
||||
# recipe_tree += [{'name': 'ld+json', 'children': temp_tree}]
|
||||
# else:
|
||||
# recipe_tree += [{'name': 'json', 'children': temp_tree}]
|
||||
|
||||
# return recipe_json, recipe_tree, html_data, images
|
||||
|
||||
|
||||
def get_from_html(soup):
|
||||
INVISIBLE_ELEMS = ('style', 'script', 'head', 'title')
|
||||
html = []
|
||||
for s in soup.strings:
|
||||
if ((s.parent.name not in INVISIBLE_ELEMS) and (len(s.strip()) > 0)):
|
||||
html.append(s)
|
||||
return html
|
||||
# def get_from_html(soup):
|
||||
# INVISIBLE_ELEMS = ('style', 'script', 'head', 'title')
|
||||
# html = []
|
||||
# for s in soup.strings:
|
||||
# if ((s.parent.name not in INVISIBLE_ELEMS) and (len(s.strip()) > 0)):
|
||||
# html.append(s)
|
||||
# return html
|
||||
|
||||
|
||||
def get_images_from_source(soup, url):
|
||||
sources = ['src', 'srcset', 'data-src']
|
||||
images = []
|
||||
img_tags = soup.find_all('img')
|
||||
if url:
|
||||
site = get_host_name(url)
|
||||
prot = url.split(':')[0]
|
||||
# def get_images_from_source(soup, url):
|
||||
# sources = ['src', 'srcset', 'data-src']
|
||||
# images = []
|
||||
# img_tags = soup.find_all('img')
|
||||
# if url:
|
||||
# site = get_host_name(url)
|
||||
# prot = url.split(':')[0]
|
||||
|
||||
urls = []
|
||||
for img in img_tags:
|
||||
for src in sources:
|
||||
try:
|
||||
urls.append(img[src])
|
||||
except KeyError:
|
||||
pass
|
||||
# urls = []
|
||||
# for img in img_tags:
|
||||
# for src in sources:
|
||||
# try:
|
||||
# urls.append(img[src])
|
||||
# except KeyError:
|
||||
# pass
|
||||
|
||||
for u in urls:
|
||||
u = u.split('?')[0]
|
||||
filename = re.search(r'/([\w_-]+[.](jpg|jpeg|gif|png))$', u)
|
||||
if filename:
|
||||
if (('http' not in u) and (url)):
|
||||
# sometimes an image source can be relative
|
||||
# if it is provide the base url
|
||||
u = '{}://{}{}'.format(prot, site, u)
|
||||
if 'http' in u:
|
||||
images.append(u)
|
||||
return images
|
||||
# for u in urls:
|
||||
# u = u.split('?')[0]
|
||||
# filename = re.search(r'/([\w_-]+[.](jpg|jpeg|gif|png))$', u)
|
||||
# if filename:
|
||||
# if (('http' not in u) and (url)):
|
||||
# # sometimes an image source can be relative
|
||||
# # if it is provide the base url
|
||||
# u = '{}://{}{}'.format(prot, site, u)
|
||||
# if 'http' in u:
|
||||
# images.append(u)
|
||||
# return images
|
||||
|
||||
|
||||
def remove_graph(el):
|
||||
# recipes type might be wrapped in @graph type
|
||||
if isinstance(el, Tag):
|
||||
try:
|
||||
el = json.loads(el.string)
|
||||
if '@graph' in el:
|
||||
for x in el['@graph']:
|
||||
if '@type' in x and x['@type'] == 'Recipe':
|
||||
el = x
|
||||
except (TypeError, JSONDecodeError):
|
||||
pass
|
||||
return el
|
||||
# def remove_graph(el):
|
||||
# # recipes type might be wrapped in @graph type
|
||||
# if isinstance(el, Tag):
|
||||
# try:
|
||||
# el = json.loads(el.string)
|
||||
# if '@graph' in el:
|
||||
# for x in el['@graph']:
|
||||
# if '@type' in x and x['@type'] == 'Recipe':
|
||||
# el = x
|
||||
# except (TypeError, JSONDecodeError):
|
||||
# pass
|
||||
# return el
|
||||
|
@ -4,17 +4,14 @@ from datetime import date, timedelta
|
||||
|
||||
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector, TrigramSimilarity
|
||||
from django.core.cache import caches
|
||||
from django.db.models import (Avg, Case, Count, Exists, F, Func, Max, OuterRef, Q, Subquery, Sum,
|
||||
Value, When)
|
||||
from django.db.models import (Avg, Case, Count, Exists, F, Func, Max, OuterRef, Q, Subquery, Value, When)
|
||||
from django.db.models.functions import Coalesce, Lower, Substr
|
||||
from django.utils import timezone, translation
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from cookbook.filters import RecipeFilter
|
||||
from cookbook.helper.HelperFunctions import Round, str2bool
|
||||
from cookbook.helper.permission_helper import has_group_permission
|
||||
from cookbook.managers import DICTIONARY
|
||||
from cookbook.models import (CookLog, CustomFilter, Food, Keyword, Recipe, RecipeBook, SearchFields,
|
||||
from cookbook.models import (CookLog, CustomFilter, Food, Keyword, Recipe, SearchFields,
|
||||
SearchPreference, ViewLog)
|
||||
from recipes import settings
|
||||
|
||||
@ -759,12 +756,3 @@ class RecipeFacet():
|
||||
else:
|
||||
return queryset.filter(depth__lte=depth).values('id', 'name', 'numchild').order_by(Lower('name').asc())
|
||||
|
||||
|
||||
def old_search(request):
|
||||
if has_group_permission(request.user, ('guest',)):
|
||||
params = dict(request.GET)
|
||||
params['internal'] = None
|
||||
f = RecipeFilter(params,
|
||||
queryset=Recipe.objects.filter(space=request.space).all().order_by(Lower('name').asc()),
|
||||
space=request.space)
|
||||
return f.qs
|
||||
|
@ -1,21 +1,19 @@
|
||||
import random
|
||||
import re
|
||||
from html import unescape
|
||||
|
||||
from pytube import YouTube
|
||||
from unicodedata import decomposition
|
||||
|
||||
from django.utils.dateparse import parse_duration
|
||||
from django.utils.translation import gettext as _
|
||||
from isodate import parse_duration as iso_parse_duration
|
||||
from isodate.isoerror import ISO8601Error
|
||||
from recipe_scrapers._utils import get_minutes
|
||||
from pytube import YouTube
|
||||
from recipe_scrapers._utils import get_host_name, get_minutes
|
||||
|
||||
from cookbook.helper import recipe_url_import as helper
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.models import Keyword
|
||||
|
||||
|
||||
# from recipe_scrapers._utils import get_minutes ## temporary until/unless upstream incorporates get_minutes() PR
|
||||
|
||||
|
||||
@ -369,3 +367,32 @@ def iso_duration_to_minutes(string):
|
||||
string
|
||||
).groupdict()
|
||||
return int(match['days'] or 0) * 24 * 60 + int(match['hours'] or 0) * 60 + int(match['minutes'] or 0)
|
||||
|
||||
|
||||
def get_images_from_soup(soup, url):
|
||||
sources = ['src', 'srcset', 'data-src']
|
||||
images = []
|
||||
img_tags = soup.find_all('img')
|
||||
if url:
|
||||
site = get_host_name(url)
|
||||
prot = url.split(':')[0]
|
||||
|
||||
urls = []
|
||||
for img in img_tags:
|
||||
for src in sources:
|
||||
try:
|
||||
urls.append(img[src])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for u in urls:
|
||||
u = u.split('?')[0]
|
||||
filename = re.search(r'/([\w_-]+[.](jpg|jpeg|gif|png))$', u)
|
||||
if filename:
|
||||
if (('http' not in u) and (url)):
|
||||
# sometimes an image source can be relative
|
||||
# if it is provide the base url
|
||||
u = '{}://{}{}'.format(prot, site, u)
|
||||
if 'http' in u:
|
||||
images.append(u)
|
||||
return images
|
||||
|
@ -1,5 +1,6 @@
|
||||
from django.urls import reverse
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from oauth2_provider.contrib.rest_framework import OAuth2Authentication
|
||||
from rest_framework.authentication import TokenAuthentication
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
@ -55,7 +56,7 @@ class ScopeMiddleware:
|
||||
else:
|
||||
if request.path.startswith(prefix + '/api/'):
|
||||
try:
|
||||
if auth := TokenAuthentication().authenticate(request):
|
||||
if auth := OAuth2Authentication().authenticate(request):
|
||||
user_space = auth[0].userspace_set.filter(active=True).first()
|
||||
if user_space:
|
||||
request.space = user_space.space
|
||||
|
@ -1,6 +1,7 @@
|
||||
from bs4 import BeautifulSoup
|
||||
from json import JSONDecodeError
|
||||
from recipe_scrapers import SCRAPERS
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from recipe_scrapers import SCRAPERS, get_host_name
|
||||
from recipe_scrapers._factory import SchemaScraperFactory
|
||||
from recipe_scrapers._schemaorg import SchemaOrg
|
||||
|
||||
@ -15,22 +16,28 @@ SCRAPERS.update(CUSTOM_SCRAPERS)
|
||||
|
||||
|
||||
def text_scraper(text, url=None):
|
||||
scraper_class = SchemaScraperFactory.SchemaScraper
|
||||
domain = None
|
||||
if url:
|
||||
domain = get_host_name(url)
|
||||
if domain in SCRAPERS:
|
||||
scraper_class = SCRAPERS[domain]
|
||||
else:
|
||||
scraper_class = SchemaScraperFactory.SchemaScraper
|
||||
|
||||
class TextScraper(scraper_class):
|
||||
def __init__(
|
||||
self,
|
||||
page_data,
|
||||
url=None
|
||||
html=None,
|
||||
url=None,
|
||||
):
|
||||
self.wild_mode = False
|
||||
self.meta_http_equiv = False
|
||||
self.soup = BeautifulSoup(page_data, "html.parser")
|
||||
self.soup = BeautifulSoup(html, "html.parser")
|
||||
self.url = url
|
||||
self.recipe = None
|
||||
try:
|
||||
self.schema = SchemaOrg(page_data)
|
||||
self.schema = SchemaOrg(html)
|
||||
except (JSONDecodeError, AttributeError):
|
||||
pass
|
||||
|
||||
return TextScraper(text, url)
|
||||
return TextScraper(url=url, html=text)
|
||||
|
@ -10,8 +10,9 @@ import validators
|
||||
import yaml
|
||||
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||
from cookbook.helper.recipe_url_import import iso_duration_to_minutes
|
||||
from cookbook.helper.recipe_url_import import (get_from_scraper, get_images_from_soup,
|
||||
iso_duration_to_minutes)
|
||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Ingredient, Keyword, Recipe, Step
|
||||
|
||||
@ -24,7 +25,10 @@ class CookBookApp(Integration):
|
||||
def get_recipe_from_file(self, file):
|
||||
recipe_html = file.getvalue().decode("utf-8")
|
||||
|
||||
recipe_json, recipe_tree, html_data, images = get_recipe_from_source(recipe_html, 'CookBookApp', self.request)
|
||||
# recipe_json, recipe_tree, html_data, images = get_recipe_from_source(recipe_html, 'CookBookApp', self.request)
|
||||
scrape = text_scraper(text=recipe_html)
|
||||
recipe_json = get_from_scraper(scrape, self.request)
|
||||
images = list(dict.fromkeys(get_images_from_soup(scrape.soup, None)))
|
||||
|
||||
recipe = Recipe.objects.create(
|
||||
name=recipe_json['name'].strip(),
|
||||
@ -42,7 +46,8 @@ class CookBookApp(Integration):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
step = Step.objects.create(instruction=recipe_json['recipeInstructions'], space=self.request.space, )
|
||||
# assuming import files only contain single step
|
||||
step = Step.objects.create(instruction=recipe_json['steps'][0]['instruction'], space=self.request.space, )
|
||||
|
||||
if 'nutrition' in recipe_json:
|
||||
step.instruction = step.instruction + '\n\n' + recipe_json['nutrition']
|
||||
@ -51,11 +56,13 @@ class CookBookApp(Integration):
|
||||
recipe.steps.add(step)
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in recipe_json['recipeIngredient']:
|
||||
f = ingredient_parser.get_food(ingredient['ingredient']['text'])
|
||||
u = ingredient_parser.get_unit(ingredient['unit']['text'])
|
||||
for ingredient in recipe_json['steps'][0]['ingredients']:
|
||||
f = ingredient_parser.get_food(ingredient['food']['name'])
|
||||
u = None
|
||||
if unit := ingredient.get('unit', None):
|
||||
u = ingredient_parser.get_unit(unit.get('name', None))
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=ingredient['amount'], note=ingredient['note'], space=self.request.space,
|
||||
food=f, unit=u, amount=ingredient.get('amount', None), note=ingredient.get('note', None), original_text=ingredient.get('original_text', None), space=self.request.space,
|
||||
))
|
||||
|
||||
if len(images) > 0:
|
||||
|
@ -2,11 +2,10 @@ import re
|
||||
from io import BytesIO
|
||||
from zipfile import ZipFile
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from bs4 import BeautifulSoup, Tag
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||
from cookbook.helper.recipe_url_import import iso_duration_to_minutes, parse_servings
|
||||
from cookbook.integration.integration import Integration
|
||||
from cookbook.models import Ingredient, Keyword, Recipe, Step
|
||||
@ -22,18 +21,21 @@ class CopyMeThat(Integration):
|
||||
|
||||
def get_recipe_from_file(self, file):
|
||||
# 'file' comes is as a beautifulsoup object
|
||||
recipe = Recipe.objects.create(name=file.find("div", {"id": "name"}).text.strip(), created_by=self.request.user, internal=True, space=self.request.space, )
|
||||
try:
|
||||
source = file.find("a", {"id": "original_link"}).text
|
||||
except AttributeError:
|
||||
source = None
|
||||
|
||||
recipe = Recipe.objects.create(name=file.find("div", {"id": "name"}).text.strip()[:128], source_url=source, created_by=self.request.user, internal=True, space=self.request.space, )
|
||||
|
||||
for category in file.find_all("span", {"class": "recipeCategory"}):
|
||||
keyword, created = Keyword.objects.get_or_create(name=category.text, space=self.request.space)
|
||||
recipe.keywords.add(keyword)
|
||||
|
||||
|
||||
try:
|
||||
recipe.servings = parse_servings(file.find("a", {"id": "recipeYield"}).text.strip())
|
||||
recipe.working_time = iso_duration_to_minutes(file.find("span", {"meta": "prepTime"}).text.strip())
|
||||
recipe.waiting_time = iso_duration_to_minutes(file.find("span", {"meta": "cookTime"}).text.strip())
|
||||
recipe.description = (file.find("div ", {"id": "description"}).text.strip())[:512]
|
||||
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@ -43,36 +45,65 @@ class CopyMeThat(Integration):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
step = Step.objects.create(instruction='', space=self.request.space, )
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
for ingredient in file.find_all("li", {"class": "recipeIngredient"}):
|
||||
if ingredient.text == "":
|
||||
continue
|
||||
amount, unit, food, note = ingredient_parser.parse(ingredient.text.strip())
|
||||
f = ingredient_parser.get_food(food)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(
|
||||
food=f, unit=u, amount=amount, note=note, original_text=ingredient.text.strip(), space=self.request.space,
|
||||
))
|
||||
|
||||
for s in file.find_all("li", {"class": "instruction"}):
|
||||
if s.text == "":
|
||||
continue
|
||||
step.instruction += s.text.strip() + ' \n\n'
|
||||
|
||||
for s in file.find_all("li", {"class": "recipeNote"}):
|
||||
if s.text == "":
|
||||
continue
|
||||
step.instruction += s.text.strip() + ' \n\n'
|
||||
|
||||
try:
|
||||
if file.find("a", {"id": "original_link"}).text != '':
|
||||
step.instruction += "\n\n" + _("Imported from") + ": " + file.find("a", {"id": "original_link"}).text
|
||||
step.save()
|
||||
if len(file.find("span", {"id": "made_this"}).text.strip()) > 0:
|
||||
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=_('I made this'))[0])
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
step = Step.objects.create(instruction='', space=self.request.space, )
|
||||
|
||||
ingredient_parser = IngredientParser(self.request, True)
|
||||
|
||||
ingredients = file.find("ul", {"id": "recipeIngredients"})
|
||||
if isinstance(ingredients, Tag):
|
||||
for ingredient in ingredients.children:
|
||||
if not isinstance(ingredient, Tag) or not ingredient.text.strip() or "recipeIngredient_spacer" in ingredient['class']:
|
||||
continue
|
||||
if any(x in ingredient['class'] for x in ["recipeIngredient_subheader", "recipeIngredient_note"]):
|
||||
step.ingredients.add(Ingredient.objects.create(is_header=True, note=ingredient.text.strip()[:256], original_text=ingredient.text.strip(), space=self.request.space, ))
|
||||
else:
|
||||
amount, unit, food, note = ingredient_parser.parse(ingredient.text.strip())
|
||||
f = ingredient_parser.get_food(food)
|
||||
u = ingredient_parser.get_unit(unit)
|
||||
step.ingredients.add(Ingredient.objects.create(food=f, unit=u, amount=amount, note=note, original_text=ingredient.text.strip(), space=self.request.space, ))
|
||||
|
||||
instructions = file.find("ol", {"id": "recipeInstructions"})
|
||||
if isinstance(instructions, Tag):
|
||||
for instruction in instructions.children:
|
||||
if not isinstance(instruction, Tag) or instruction.text == "":
|
||||
continue
|
||||
if "instruction_subheader" in instruction['class']:
|
||||
if step.instruction:
|
||||
step.save()
|
||||
recipe.steps.add(step)
|
||||
step = Step.objects.create(instruction='', space=self.request.space, )
|
||||
|
||||
step.name = instruction.text.strip()[:128]
|
||||
else:
|
||||
step.instruction += instruction.text.strip() + ' \n\n'
|
||||
|
||||
notes = file.find_all("li", {"class": "recipeNote"})
|
||||
if notes:
|
||||
step.instruction += '*Notes:* \n\n'
|
||||
|
||||
for n in notes:
|
||||
if n.text == "":
|
||||
continue
|
||||
step.instruction += '*' + n.text.strip() + '* \n\n'
|
||||
|
||||
description = ''
|
||||
try:
|
||||
description = file.find("div", {"id": "description"}).text.strip()
|
||||
except AttributeError:
|
||||
pass
|
||||
if len(description) <= 512:
|
||||
recipe.description = description
|
||||
else:
|
||||
recipe.description = description[:480] + ' ... (full description below)'
|
||||
step.instruction += '*Description:* \n\n*' + description + '* \n\n'
|
||||
|
||||
step.save()
|
||||
recipe.steps.add(step)
|
||||
|
||||
# import the Primary recipe image that is stored in the Zip
|
||||
|
@ -43,7 +43,7 @@ class Integration:
|
||||
self.export_type = export_type
|
||||
self.ignored_recipes = []
|
||||
|
||||
description = f'Imported by {request.user.get_user_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}. Type: {export_type}'
|
||||
description = f'Imported by {request.user.get_user_display_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}. Type: {export_type}'
|
||||
icon = '📥'
|
||||
|
||||
try:
|
||||
@ -169,7 +169,7 @@ class Integration:
|
||||
|
||||
for z in file_list:
|
||||
try:
|
||||
if not hasattr(z, 'filename'):
|
||||
if not hasattr(z, 'filename') or type(z) == Tag:
|
||||
recipe = self.get_recipe_from_file(z)
|
||||
else:
|
||||
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
|
||||
|
BIN
cookbook/locale/ar/LC_MESSAGES/django.mo
Normal file
BIN
cookbook/locale/ar/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2022-05-22 11:20+0000\n"
|
||||
"Last-Translator: Ramon Aixa Juan <juanramonaixa@gmail.com>\n"
|
||||
"Language-Team: Catalan <http://translate.tandoor.dev/projects/tandoor/"
|
||||
@ -535,7 +535,7 @@ msgstr "Has arribat al nombre màxim de receptes per al vostre espai."
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr "Tens més usuaris dels permesos al teu espai."
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr "S'ha de proporcionar una de queryset o hash_key"
|
||||
|
||||
@ -548,12 +548,12 @@ msgstr "Heu de proporcionar una mida de porcions"
|
||||
msgid "Could not parse template code."
|
||||
msgstr "No s'ha pogut analitzar el codi de la plantilla."
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -692,104 +692,104 @@ msgstr "Nova"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr " forma part d'un pas de recepta i no es pot suprimir"
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr "Simple"
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr "Frase"
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr "Web"
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr "Cru"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr "Alies Menjar"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr "Àlies Unitat"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Àlies Paraula clau"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Recepta"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "Foods"
|
||||
msgid "Food"
|
||||
msgstr "Menjars"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Paraula Clau"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr "Càrregues de fitxers no habilitades en aquest espai."
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr "Límit de càrrega de fitxers Assolit."
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr "Hola"
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr "Convidat per "
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr " per unir-se al seu espai de Receptes "
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr "Click per activar el teu compte: "
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
"Si l'enllaç no funciona, utilitzeu el codi següent per unir-vos a l'espai: "
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr "Invitació vàlida fins "
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
"Tandoor Recipes és un gestor de receptes de codi obert. Comprova a GitHub "
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr "Invitació de receptes Tandoor"
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr "Llista de la compra existent a actualitzar"
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
@ -797,22 +797,22 @@ msgstr ""
|
||||
"Llista d'ingredients IDs de la recepta per afegir, si no es proporciona, "
|
||||
"s'afegiran tots els ingredients."
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
"Proporcionant un list_recipe ID i porcions de 0, se suprimirà aquesta llista "
|
||||
"de la compra."
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr "Quantitat de menjar per afegir a la llista de la compra"
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr "ID de la unitat a utilitzar per a la llista de la compra"
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
"Quan s'estableix a true, se suprimirà tots els aliments de les llistes de "
|
||||
@ -956,7 +956,7 @@ msgstr ""
|
||||
"confirmació d'email</a>."
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Iniciar Sessió"
|
||||
|
||||
@ -1123,7 +1123,7 @@ msgstr "Inicis Tancats"
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr "Inicis de Sessió tancats temporalment."
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "Documentació API"
|
||||
@ -1220,36 +1220,36 @@ msgstr "Admin"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Sense Espai"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Guia Markdown"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr "Tradueix Tandoor"
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "Navegador API"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr "Tanca sessió"
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2263,19 +2263,11 @@ msgstr "Receptes sense paraules clau"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Receptes Internes"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Enllaços Invitació"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Mostra Enllaços"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Informació de Sistema"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2293,21 +2285,21 @@ msgstr ""
|
||||
"com/vabene1111/recipes/releases\">aquí</a>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "Servei Mitjans"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Advertència"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "Ok"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2323,16 +2315,16 @@ msgstr ""
|
||||
"a> per actualitzar\n"
|
||||
"la vostra instal·lació."
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "Tot està bé!"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Paraula Clau"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2352,11 +2344,11 @@ msgstr ""
|
||||
"Estableix-ho\n"
|
||||
"<code>SECRET_KEY</code> al fitxer de configuració<code> .env.</code>"
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Mode Depuració"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2372,15 +2364,15 @@ msgstr ""
|
||||
"configuració\n"
|
||||
"<code>DEBUG = 0</code> al fitxer de configuració<code> .env.</code>"
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Base de Dades"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2397,72 +2389,72 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "Importació d’URL"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "El paràmetre updated_at té un format incorrecte"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr "No {self.basename} amb id {pk} existeix"
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr "No es pot fusionar amb el mateix objecte!"
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr "No {self.basename} amb id {target} existeix"
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr "No es pot combinar amb l'objecte fill!"
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr "{source.name} s'ha fusionat amb {target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr "Error en intentar combinar {source.name} amb {target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr "{child.name} s'ha mogut correctament a l'arrel."
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr "Error a l'intentar moure "
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr "No es pot moure un objecte cap a si mateix!"
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr "No existeix {self.basename} amb identificador {parent}"
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr "{child.name} s'ha mogut correctament al pare {parent.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr "{obj.name} eliminat de la llista de la compra."
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr "Afegit {obj.name} a la llista de la compra."
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr "ID de recepta forma part d'un pas. Per a múltiples repeteix paràmetre."
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr "La cadena de consulta coincideix (difusa) amb el nom de l'objecte."
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
@ -2470,7 +2462,7 @@ msgstr ""
|
||||
"Cadena de consulta coincideix (difusa) amb el nom de la recepta. En el futur "
|
||||
"també cerca text complet."
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
#, fuzzy
|
||||
#| msgid "ID of keyword a recipe should have. For multiple repeat parameter."
|
||||
msgid ""
|
||||
@ -2480,173 +2472,173 @@ msgstr ""
|
||||
"ID de la paraula clau que hauria de tenir una recepta. Per a múltiples "
|
||||
"repeteix paràmetre."
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"ID d'aliments que ha de tenir una recepta. Per a múltiples repeteix "
|
||||
"paràmetres."
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr "ID d'unitat que hauria de tenir una recepta."
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"ID del llibre hauria d'haver-hi en una recepta. Per al paràmetre de "
|
||||
"repetició múltiple."
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr "Res a fer."
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr "Connexió Refusada."
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
msgid "No usable data could be found."
|
||||
msgstr "No s'han trobat dades utilitzables."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
"Aquesta funció encara no està disponible a la versió allotjada de tandoor!"
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "Sincronització correcte"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Error de sincronització amb emmagatzematge"
|
||||
|
||||
@ -2736,6 +2728,10 @@ msgstr "Descobriment"
|
||||
msgid "Shopping List"
|
||||
msgstr "Llista de la Compra"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Enllaços Invitació"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr "Supermercats"
|
||||
@ -2844,6 +2840,9 @@ msgstr ""
|
||||
"L'enllaç per compartir receptes s'ha desactivat! Per obtenir informació "
|
||||
"addicional, poseu-vos en contacte amb l'administrador."
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Mostra Enllaços"
|
||||
|
||||
#~ msgid "A user is required"
|
||||
#~ msgstr "Usuari requerit"
|
||||
|
||||
|
@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-04-29 18:42+0200\n"
|
||||
"PO-Revision-Date: 2022-05-10 15:32+0000\n"
|
||||
"PO-Revision-Date: 2022-08-18 14:32+0000\n"
|
||||
"Last-Translator: Mathias Rasmussen <math625f@gmail.com>\n"
|
||||
"Language-Team: Danish <http://translate.tandoor.dev/projects/tandoor/"
|
||||
"recipes-backend/da/>\n"
|
||||
@ -2377,9 +2377,9 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
"At servere mediefiler direkte med gunicorn/python er <b>ikke anbefalet</b>!\n"
|
||||
" Følg venligst trinne beskrevet\n"
|
||||
" Følg venligst trinnene beskrevet\n"
|
||||
" <a href=\"https://github.com/vabene1111/recipes/releases/tag/0.8.1\""
|
||||
">here</a> for at opdtere\n"
|
||||
">her</a> for at opdatere\n"
|
||||
" din installation.\n"
|
||||
" "
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -471,7 +471,7 @@ msgstr ""
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -484,12 +484,12 @@ msgstr ""
|
||||
msgid "Could not parse template code."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -620,119 +620,119 @@ msgstr ""
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
msgid "Food"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -864,7 +864,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
@ -1028,7 +1028,7 @@ msgstr ""
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr ""
|
||||
@ -1121,36 +1121,36 @@ msgstr ""
|
||||
msgid "Your Spaces"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2091,19 +2091,11 @@ msgstr ""
|
||||
msgid "Internal Recipes"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2114,21 +2106,21 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2138,16 +2130,16 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2160,11 +2152,11 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2175,15 +2167,15 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2196,245 +2188,245 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
msgid "No usable data could be found."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr ""
|
||||
|
||||
@ -2517,6 +2509,10 @@ msgstr ""
|
||||
msgid "Shopping List"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr ""
|
||||
|
@ -13,9 +13,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"PO-Revision-Date: 2022-06-25 17:32+0000\n"
|
||||
"Last-Translator: César Blanco Guillamon <cesarblancg97@gmail.com>\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2022-08-12 21:32+0000\n"
|
||||
"Last-Translator: Thorin <thorin8@hotmail.com>\n"
|
||||
"Language-Team: Spanish <http://translate.tandoor.dev/projects/tandoor/"
|
||||
"recipes-backend/es/>\n"
|
||||
"Language: es\n"
|
||||
@ -68,7 +68,7 @@ msgstr "Estilo de búsqueda"
|
||||
|
||||
#: .\cookbook\forms.py:62
|
||||
msgid "Plan sharing"
|
||||
msgstr ""
|
||||
msgstr "Compartir régimen"
|
||||
|
||||
#: .\cookbook\forms.py:63
|
||||
msgid "Ingredient decimal places"
|
||||
@ -518,7 +518,7 @@ msgstr ""
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -531,12 +531,12 @@ msgstr "Debe proporcionar un tamaño de porción"
|
||||
msgid "Could not parse template code."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -669,125 +669,125 @@ msgstr "Nuevo"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr "Alias de la Comida"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Units"
|
||||
msgid "Unit Alias"
|
||||
msgstr "Unidades"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Keywords"
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Palabras clave"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Receta"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "Food"
|
||||
msgid "Food"
|
||||
msgstr "Comida"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Palabra clave"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -921,7 +921,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Iniciar sesión"
|
||||
|
||||
@ -1096,7 +1096,7 @@ msgstr ""
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "Documentación de API"
|
||||
@ -1203,36 +1203,36 @@ msgstr "Administrador"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Crear Usuario"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Guia Markdown"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "Explorador de API"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2278,19 +2278,11 @@ msgstr "Recetas sin palabras clave"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Recetas Internas"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Enlaces de Invitación"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Mostrar Enlaces"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Información del Sistema"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2308,21 +2300,21 @@ msgstr ""
|
||||
"github.com/vabene1111/recipes/releases\">aquí</a>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "Servidor multimedia"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Advertencia"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "Ok"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2339,16 +2331,16 @@ msgstr ""
|
||||
" tu instalación.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "¡Todo va bien!"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Clave Secreta"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2370,11 +2362,11 @@ msgstr ""
|
||||
"env</code>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Modo Depuración"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2392,15 +2384,15 @@ msgstr ""
|
||||
"code>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Base de Datos"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Información"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2418,253 +2410,253 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "Importar URL"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
#, fuzzy
|
||||
#| msgid "Parameter filter_list incorrectly formatted"
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "Parámetro filter_list formateado incorrectamente"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr "¡No se puede unir con el mismo objeto!"
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
#, fuzzy
|
||||
#| msgid "Cannot merge with the same object!"
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr "¡No se puede unir con el mismo objeto!"
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
#, fuzzy
|
||||
#| msgid "The requested page could not be found."
|
||||
msgid "No usable data could be found."
|
||||
msgstr "La página solicitada no pudo ser encontrada."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
#, fuzzy
|
||||
#| msgid "This feature is not available in the demo version!"
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr "¡Esta funcionalidad no está disponible en la versión demo!"
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "¡Sincronización exitosa!"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Error de sincronización con el almacenamiento"
|
||||
|
||||
@ -2749,6 +2741,10 @@ msgstr "Descubrimiento"
|
||||
msgid "Shopping List"
|
||||
msgstr "Lista de la Compra"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Enlaces de Invitación"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
#, fuzzy
|
||||
#| msgid "Supermarket"
|
||||
@ -2853,6 +2849,9 @@ msgid ""
|
||||
"contact the page administrator."
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Mostrar Enlaces"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Invite Links"
|
||||
#~ msgid "Invite User"
|
||||
|
@ -13,7 +13,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2022-02-09 01:31+0000\n"
|
||||
"Last-Translator: Marion Kämpfer <marion@murphyslantech.de>\n"
|
||||
"Language-Team: French <http://translate.tandoor.dev/projects/tandoor/recipes-"
|
||||
@ -562,7 +562,7 @@ msgstr ""
|
||||
"Le nombre d’utilisateurs dans votre groupe dépasse le nombre d’utilisateurs "
|
||||
"autorisé."
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -577,12 +577,12 @@ msgstr "Vous devez fournir une information créé_par"
|
||||
msgid "Could not parse template code."
|
||||
msgstr "Impossible d’analyser le code du modèle."
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -723,125 +723,125 @@ msgstr "Nouveau"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr " fait partie d’une étape de la recette et ne peut être supprimé(e)"
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr "Simple"
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr "Phrase"
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr "Internet"
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr "Brut"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr "Aliment équivalent"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr "Unité équivalente"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Mot-clé équivalent"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Recette"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "Foods"
|
||||
msgid "Food"
|
||||
msgstr "Aliments"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Mot-clé"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr "Le téléversement de fichiers n’est pas autorisé pour ce groupe."
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr "Vous avez atteint votre limite de téléversement de fichiers."
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr "Bonjour"
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr "Vous avez été invité par "
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr " pour rejoindre leur groupe Tandoor Recipes "
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr "Cliquez le lien suivant pour activer votre compte : "
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
"Si le lien ne fonctionne pas, utilisez le code suivant pour rejoindre le "
|
||||
"groupe manuellement : "
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr "L’invitation est valide jusqu’au "
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
"Tandoor Recipes est un gestionnaire de recettes open source. Venez-voir "
|
||||
"notre Github "
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr "Invitation Tandoor Recipes"
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr "Liste de courses existante à mettre à jour"
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr "Quantité d’aliments à ajouter à la liste de courses"
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr "ID de l’unité à utiliser pour la liste de courses"
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -981,7 +981,7 @@ msgstr ""
|
||||
"par mail</a>."
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Connexion"
|
||||
|
||||
@ -1154,7 +1154,7 @@ msgstr "Inscriptions closes"
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr "Nous sommes désolés, mais les inscriptions sont closes pour le moment."
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "Documentation API"
|
||||
@ -1251,36 +1251,36 @@ msgstr "Admin"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Aucun groupe"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Guide Markdown"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr "Traduire Tandoor"
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "Navigateur API"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2473,19 +2473,11 @@ msgstr "Recettes sans mots-clés"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Recettes internes"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Liens d’invitation"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Afficher les liens"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Informations système"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2503,21 +2495,21 @@ msgstr ""
|
||||
"github.com/vabene1111/recipes/releases\">ici</a>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "Publication des médias"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Avertissement"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "OK"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2533,16 +2525,16 @@ msgstr ""
|
||||
" pour mettre à jour votre installation.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "Tout est en ordre !"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Clé secrète"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2563,11 +2555,11 @@ msgstr ""
|
||||
"env</code>\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Mode debug"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2584,15 +2576,15 @@ msgstr ""
|
||||
"code>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Base de données"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2611,251 +2603,251 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "Import URL"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "Le paramètre « update_at » n'est pas correctement formaté"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr "Il n’existe aucun(e) {self.basename} avec l’identifiant {pk}"
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr "Impossible de fusionner un objet avec lui-même !"
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr "Il n’existe aucun(e) {self.basename} avec l’id {target}"
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr "Impossible de fusionner avec l’objet enfant !"
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr "{source.name} a été fusionné avec succès avec {target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
"Une erreur est survenue lors de la tentative de fusion de {source.name} avec "
|
||||
"{target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr "{child.name} a été déplacé avec succès vers la racine."
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr "Une erreur est survenue en essayant de déplacer "
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr "Impossible de déplacer un objet vers lui-même !"
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr "Il n’existe aucun(e) {self.basename} avec l’id {parent}"
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr "{child.name} a été déplacé avec succès vers le parent {parent.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr "{obj.name} a été supprimé(e) de la liste de courses."
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr "{obj.name} a été ajouté(e) à la liste de courses."
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr "Rien à faire."
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr "Connexion refusée."
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
#, fuzzy
|
||||
#| msgid "No useable data could be found."
|
||||
msgid "No usable data could be found."
|
||||
msgstr "Aucune information utilisable n'a été trouvée."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
"Cette fonctionnalité n’est pas encore disponible dans la version hébergée de "
|
||||
"Tandoor !"
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "Synchro réussie !"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Erreur lors de la synchronisation avec le stockage"
|
||||
|
||||
@ -2943,6 +2935,10 @@ msgstr "Découverte"
|
||||
msgid "Shopping List"
|
||||
msgstr "Liste de courses"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Liens d’invitation"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr "Supermarchés"
|
||||
@ -3055,6 +3051,9 @@ msgstr ""
|
||||
"Le lien de partage de la recette a été désactivé ! Pour plus d’informations, "
|
||||
"veuillez contacter l’administrateur de la page."
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Afficher les liens"
|
||||
|
||||
#~ msgid "A user is required"
|
||||
#~ msgstr "Un utilisateur est requis"
|
||||
|
||||
|
@ -10,7 +10,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2022-05-24 20:32+0000\n"
|
||||
"Last-Translator: Krisztian Doka <master@dnome.hu>\n"
|
||||
"Language-Team: Hungarian <http://translate.tandoor.dev/projects/tandoor/"
|
||||
@ -547,7 +547,7 @@ msgstr "Elérte a maximális számú receptet a helyén."
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr "Több felhasználója van, mint amennyit engedélyeztek a térben."
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr "A queryset vagy a hash_key valamelyikét meg kell adni"
|
||||
|
||||
@ -562,12 +562,12 @@ msgstr "Meg kell adnia egy created_by"
|
||||
msgid "Could not parse template code."
|
||||
msgstr "Nem sikerült elemezni a sablon kódját."
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
#, fuzzy
|
||||
@ -710,105 +710,105 @@ msgstr "Új"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr " egy recept része, ezért nem törölhető"
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr "Egyszerű"
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr "Kifejezés"
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr "Web"
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr "Nyers"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr "Élelmiszer álneve"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr "Egység álneve"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Kulcsszó álneve"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Recept"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "Foods"
|
||||
msgid "Food"
|
||||
msgstr "Ételek"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Kulcsszó"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr "A fájlok feltöltése nem engedélyezett ezen a tárhelyen."
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr "Elérte a fájlfeltöltési limitet."
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr "Helló"
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr "Önt meghívta "
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr " hogy csatlakozzon a Tandoor Receptek helyhez "
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr "Kattintson az alábbi linkre fiókja aktiválásához: "
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
"Ha a link nem működik, használja a következő kódot, hogy manuálisan "
|
||||
"csatlakozzon a térhez: "
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr "A meghívó a következő időpontig érvényes "
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
"A Tandoor Receptek egy nyílt forráskódú receptkezelő. Nézze meg a GitHubon "
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr "Tandoor receptek meghívó"
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr "Meglévő bevásárlólista frissítése"
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
@ -816,20 +816,20 @@ msgstr ""
|
||||
"A hozzáadandó összetevők azonosítóinak listája a receptből, ha nincs "
|
||||
"megadva, az összes összetevő hozzáadásra kerül."
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr "A list_recipe azonosító és a 0 adag megadása törli a bevásárlólistát."
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr "A bevásárlólistához hozzáadandó élelmiszerek mennyisége"
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr "A bevásárlólistához használandó egység azonosítója"
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
"Ha igazra van állítva, akkor minden élelmiszert töröl az aktív "
|
||||
@ -972,7 +972,7 @@ msgstr ""
|
||||
"kérelmet</a>."
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Bejelentkezés"
|
||||
|
||||
@ -1144,7 +1144,7 @@ msgstr "Regisztráció lezárva"
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr "Sajnáljuk, de a regisztráció jelenleg zárva van."
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "API dokumentáció"
|
||||
@ -1241,36 +1241,36 @@ msgstr "Admin"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Nincs hely"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Markdown útmutató"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr "Tandoor fordítása"
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "API böngésző"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr "Kijelentkezés"
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2444,19 +2444,11 @@ msgstr "Receptek kulcsszavak nélkül"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Belső receptek"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Meghívó linkek"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Linkek megjelenítése"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Rendszerinformáció"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2474,21 +2466,21 @@ msgstr ""
|
||||
"vabene1111/recipes/releases\">itt</a>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "Média kiszolgáló"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Figyelmeztetés"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "Rendben"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2505,16 +2497,16 @@ msgstr ""
|
||||
" frissítéshez.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "Minden rendben van!"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Titkos kulcs"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2536,11 +2528,11 @@ msgstr ""
|
||||
"fájlban.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Hibakeresési mód"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2558,15 +2550,15 @@ msgstr ""
|
||||
"konfigurációs fájlban.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Adatbázis"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Információ"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2584,74 +2576,74 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "URL importálása"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "Az updated_at paraméter helytelenül van formázva"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr "Nem létezik {self.basename} azonosítóval {pk}"
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr "Nem egyesíthető ugyanazzal az objektummal!"
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr "Nem létezik {self.basename} azonosítóval {target}"
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr "Nem lehet egyesíteni a gyermekobjektummal!"
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr "{source.name} sikeresen egyesült a {target.name} -vel"
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr "Hiba történt a {source.name} és a {target.name} egyesítése során"
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr "{child.name} sikeresen átkerült a gyökérbe."
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr "Hiba történt az áthelyezés közben "
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr "Nem lehet egy objektumot önmagába mozgatni!"
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr "Nem létezik {self.basename} azonosítóval {parent}"
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr "{child.name} sikeresen átkerült a {parent.name} szülőhöz"
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr "{obj.name} lekerült a bevásárlólistáról."
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr "{obj.name} hozzá lett adva a bevásárlólistához."
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"A recept azonosítója, amelynek egy lépés része. Többszörös ismétlés esetén "
|
||||
"paraméter."
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr "A lekérdezés karakterlánca az objektum nevével összevetve (fuzzy)."
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
@ -2659,7 +2651,7 @@ msgstr ""
|
||||
"A lekérdezési karakterláncot a recept nevével összevetve (fuzzy). A jövőben "
|
||||
"teljes szöveges keresés is."
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
#, fuzzy
|
||||
#| msgid "ID of keyword a recipe should have. For multiple repeat parameter."
|
||||
msgid ""
|
||||
@ -2668,132 +2660,132 @@ msgid ""
|
||||
msgstr ""
|
||||
"A recept kulcsszavának azonosítója. Többszörös ismétlődő paraméter esetén."
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"Az ételek azonosítója egy receptnek tartalmaznia kell. Többszörös ismétlődő "
|
||||
"paraméter esetén."
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr "Az egység azonosítója, amellyel a receptnek rendelkeznie kell."
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"A könyv azonosítója, amelyben a receptnek szerepelnie kell. Többszörös "
|
||||
"ismétlés esetén paraméter."
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr "Ha csak a belső recepteket kell visszaadni. [true/<b>false</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
"Az eredményeket véletlenszerű sorrendben adja vissza. [true/<b>false</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
"Az új találatokat adja vissza először a keresési eredmények között. [true/"
|
||||
"<b>false</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
#, fuzzy
|
||||
#| msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr "Ha csak a belső recepteket kell visszaadni. [true/<b>false</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
@ -2801,7 +2793,7 @@ msgstr ""
|
||||
"Visszaadja az id elsődleges kulccsal rendelkező bevásárlólista-bejegyzést. "
|
||||
"Több érték megengedett."
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
@ -2810,44 +2802,44 @@ msgstr ""
|
||||
"mindkettő, <b>legutóbbi</b>]<br> – a legutóbbi a nem bejelölt és a nemrég "
|
||||
"befejezett elemeket tartalmazza."
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
"Visszaadja a bevásárlólista bejegyzéseit szupermarket kategóriák szerinti "
|
||||
"sorrendben."
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr "Semmi feladat."
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr "Kapcsolat megtagadva."
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
#, fuzzy
|
||||
#| msgid "No useable data could be found."
|
||||
msgid "No usable data could be found."
|
||||
msgstr "Nem találtam használható adatokat."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr "Ez a funkció még nem érhető el a tandoor hosztolt verziójában!"
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "Szinkronizálás sikeres!"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Hiba szinkronizálás közben a tárolóval"
|
||||
|
||||
@ -2936,6 +2928,10 @@ msgstr "Felfedezés"
|
||||
msgid "Shopping List"
|
||||
msgstr "Bevásárlólista"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Meghívó linkek"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr "Szupermarketek"
|
||||
@ -3044,6 +3040,9 @@ msgstr ""
|
||||
"A receptmegosztó linket letiltották! További információkért kérjük, "
|
||||
"forduljon az oldal adminisztrátorához."
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Linkek megjelenítése"
|
||||
|
||||
#~ msgid "A user is required"
|
||||
#~ msgstr "Egy felhasználó szükséges"
|
||||
|
||||
|
@ -11,8 +11,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"PO-Revision-Date: 2022-06-01 22:32+0000\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2022-08-04 11:32+0000\n"
|
||||
"Last-Translator: Oliver Cervera <olivercervera@yahoo.it>\n"
|
||||
"Language-Team: Italian <http://translate.tandoor.dev/projects/tandoor/"
|
||||
"recipes-backend/it/>\n"
|
||||
@ -330,12 +330,16 @@ msgid ""
|
||||
"Fields to search ignoring accents. Selecting this option can improve or "
|
||||
"degrade search quality depending on language"
|
||||
msgstr ""
|
||||
"Campi da cercare ignorando gli accenti. A seconda alla lingua utilizzata, "
|
||||
"questa opzione può migliorare o peggiorare la ricerca"
|
||||
|
||||
#: .\cookbook\forms.py:453
|
||||
msgid ""
|
||||
"Fields to search for partial matches. (e.g. searching for 'Pie' will return "
|
||||
"'pie' and 'piece' and 'soapie')"
|
||||
msgstr ""
|
||||
"Campi da cercare con corrispondenza parziale. (ad esempio, cercando \"Torta"
|
||||
"\" verranno mostrati \"torta\", \"tortino\" e \"contorta\")"
|
||||
|
||||
#: .\cookbook\forms.py:455
|
||||
msgid ""
|
||||
@ -543,7 +547,7 @@ msgstr "Hai raggiunto il numero massimo di ricette nella tua istanza."
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr "Hai più utenti di quanti permessi nella tua istanza."
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -558,12 +562,12 @@ msgstr "Devi fornire almeno una ricetta o un titolo."
|
||||
msgid "Could not parse template code."
|
||||
msgstr "Impossibile elaborare il codice del template."
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -704,125 +708,125 @@ msgstr "Nuovo"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr " è parte dello step di una ricetta e non può essere eliminato"
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr "Semplice"
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr "Frase"
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr "Web"
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr "Raw"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr "Alias Alimento"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr "Alias Unità"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Alias Parola Chiave"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Ricetta"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "Foods"
|
||||
msgid "Food"
|
||||
msgstr "Alimenti"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Parola chiave"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr "Il caricamento dei file non è abilitato in questa istanza."
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr "Hai raggiungo il limite per il caricamento dei file."
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr "Ciao"
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr "Sei stato invitato da "
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr " per entrare nella sua istanza di Tandoor Recipes "
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr "Clicca il link qui di seguito per attivare il tuo account: "
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
"Se il link non funziona, usa il seguente codice per entrare manualmente "
|
||||
"nell'istanza: "
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr "L'invito è valido fino al "
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
"Tandoor Recipes è un gestore di ricette Open Source. Dagli una occhiata su "
|
||||
"GitHub "
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr "Invito per Tandoor Recipes"
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -963,7 +967,7 @@ msgstr ""
|
||||
"a>."
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Login"
|
||||
|
||||
@ -1135,7 +1139,7 @@ msgstr "Iscrizioni chiuse"
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr "Spiacenti, al momento le iscrizioni sono chiuse."
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "Documentazione API"
|
||||
@ -1232,36 +1236,36 @@ msgstr "Amministratore"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Nessuna istanza"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Informazioni su Markdown"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr "Traduci Tandoor"
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "Browser API"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr "Esci"
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2296,19 +2300,11 @@ msgstr "Ricette senza parole chiave"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Ricette interne"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Link di invito"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Mostra link"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Informazioni di sistema"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2324,21 +2320,21 @@ msgstr ""
|
||||
"Le ultime novità sono disponibili <a href=\"https://github.com/vabene1111/"
|
||||
"recipes/releases\">qui</a>."
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "File multimediali"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Avviso"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "Ok"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2353,16 +2349,16 @@ msgstr ""
|
||||
"<a href=\"https://github.com/vabene1111/recipes/releases/tag/0.8.1\">qui</a> "
|
||||
"per aggiornare la tua installazione."
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "È tutto ok!"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Chiave segreta"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2380,11 +2376,11 @@ msgstr ""
|
||||
"dell'installazione che è pubblica e insicura! Sei pregato di aggiungere una\n"
|
||||
"<code>SECRET_KEY</code> nel file di configurazione <code>.env</code>."
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Modalità di debug"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2400,15 +2396,15 @@ msgstr ""
|
||||
"configurando\n"
|
||||
"<code>DEBUG=0</code> nel file di configurazione<code>.env</code>."
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Database"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2425,251 +2421,251 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "Importa da URL"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "Il parametro updated_at non è formattato correttamente"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr "Non esiste nessun {self.basename} con id {pk}"
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr "Non è possibile unirlo con lo stesso oggetto!"
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr "Non esiste nessun {self.basename} con id {target}"
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr "Non è possibile unirlo con un oggetto secondario!"
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr "{source.name} è stato unito con successo a {target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
"Si è verificato un errore durante l'unione di {source.name} con {target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr "{child.name} è stato spostato con successo alla radice."
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr "Si è verificato un errore durante lo spostamento "
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr "Non è possibile muovere un oggetto a sé stesso!"
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr "Non esiste nessun {self.basename} con id {parent}"
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr "{child.name} è stato spostato con successo al primario {parent.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
"Filtra le ricette che possono essere preparate con alimenti già disponibili. "
|
||||
"[true/<b>false</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr "Nulla da fare."
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
#, fuzzy
|
||||
#| msgid "No useable data could be found."
|
||||
msgid "No usable data could be found."
|
||||
msgstr "Nessuna informazione utilizzabile è stata trovata."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
"Questa funzione non è ancora disponibile nella versione hostata di Tandor!"
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "Sincronizzazione completata con successo!"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Errore di sincronizzazione con questo backend"
|
||||
|
||||
@ -2759,6 +2755,10 @@ msgstr "Trovate"
|
||||
msgid "Shopping List"
|
||||
msgstr "Lista della spesa"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Link di invito"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr "Supermercati"
|
||||
@ -2867,6 +2867,9 @@ msgstr ""
|
||||
"Il link per la condivisione delle ricette è stato disabilitato! Per maggiori "
|
||||
"informazioni contatta l'amministratore."
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Mostra link"
|
||||
|
||||
#~ msgid "Invite User"
|
||||
#~ msgstr "Invita utente"
|
||||
|
||||
|
@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2020-06-02 19:28+0000\n"
|
||||
"Last-Translator: vabene1111 <vabene1234@googlemail.com>, 2021\n"
|
||||
"Language-Team: Latvian (https://www.transifex.com/django-recipes/"
|
||||
@ -525,7 +525,7 @@ msgstr ""
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -540,12 +540,12 @@ msgstr "Jums jānorāda vismaz recepte vai nosaukums."
|
||||
msgid "Could not parse template code."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -681,127 +681,127 @@ msgstr "Jauns"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Food"
|
||||
msgid "Food Alias"
|
||||
msgstr "Ēdiens"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Units"
|
||||
msgid "Unit Alias"
|
||||
msgstr "Vienības"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Keywords"
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Atslēgvārdi"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Recepte"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "Food"
|
||||
msgid "Food"
|
||||
msgstr "Ēdiens"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Atslēgvārds"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -937,7 +937,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Pieslēgties"
|
||||
|
||||
@ -1111,7 +1111,7 @@ msgstr ""
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "API dokumentācija"
|
||||
@ -1218,36 +1218,36 @@ msgstr "Administrators"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Izveidot lietotāju"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Markdown rokasgrāmata"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "Github"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "API pārlūks"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2273,19 +2273,11 @@ msgstr "Receptes bez atslēgas vārdiem"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Iekšējās receptes"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Uzaicinājuma saites"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Rādīt saites"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Sistēmas informācija"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2303,21 +2295,21 @@ msgstr ""
|
||||
"recipes/releases\">šeit</a>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "Multivides rādīšana"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Brīdinājums"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "Ok"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2334,16 +2326,16 @@ msgstr ""
|
||||
" jūsu instalāciju.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "Viss ir kārtībā!"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Slepenā atslēga"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2365,11 +2357,11 @@ msgstr ""
|
||||
"code>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Atkļūdošanas režīms"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2386,15 +2378,15 @@ msgstr ""
|
||||
" <code>DEBUG = 0</code> konfigurācijas failā <code>.env</code>.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Datubāze"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2412,249 +2404,249 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "URL importēšana"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
#, fuzzy
|
||||
#| msgid "Parameter filter_list incorrectly formatted"
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "Parametrs filter_list ir nepareizi formatēts"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
#, fuzzy
|
||||
#| msgid "The requested page could not be found."
|
||||
msgid "No usable data could be found."
|
||||
msgstr "Pieprasīto lapu nevarēja atrast."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "Sinhronizācija ir veiksmīga!"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Sinhronizējot ar krātuvi, radās kļūda"
|
||||
|
||||
@ -2740,6 +2732,10 @@ msgstr "Atklāšana"
|
||||
msgid "Shopping List"
|
||||
msgstr "Iepirkumu saraksts"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Uzaicinājuma saites"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr ""
|
||||
@ -2842,6 +2838,9 @@ msgid ""
|
||||
"contact the page administrator."
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Rādīt saites"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Invite Links"
|
||||
#~ msgid "Invite User"
|
||||
|
@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2022-05-31 08:32+0000\n"
|
||||
"Last-Translator: Jesse <jesse.kamps@pm.me>\n"
|
||||
"Language-Team: Dutch <http://translate.tandoor.dev/projects/tandoor/recipes-"
|
||||
@ -531,7 +531,7 @@ msgstr "Je hebt het maximaal aantal recepten voor jouw ruimte bereikt."
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr "Je hebt meer gebruikers dan toegestaan in jouw ruimte."
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr "Er moet een queryset of hash_key opgegeven worden"
|
||||
|
||||
@ -544,12 +544,12 @@ msgstr "Je moet een portiegrootte aanleveren"
|
||||
msgid "Could not parse template code."
|
||||
msgstr "Sjablooncode kon niet verwerkt worden."
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr "Favoriet"
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -687,103 +687,103 @@ msgstr "Nieuw"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr " is deel van een receptstap en kan niet verwijderd worden"
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr "Simpel"
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr "Zin"
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr "Web"
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr "Rauw"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr "Ingrediënt alias"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr "Eenheid alias"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Etiket alias"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Recept"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
msgid "Food"
|
||||
msgstr "Ingrediënt"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Etiket"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr "Bestandsuploads zijn niet ingeschakeld voor deze Ruimte."
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr "U heeft de uploadlimiet bereikt."
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr "Hallo"
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr "Je bent uitgenodigd door "
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr " om zijn/haar Tandoor Recepten ruimte "
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr "Klik om de volgende link om je account te activeren: "
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
"Als de linkt niet werkt, gebruik dan de volgende code om handmatig tot de "
|
||||
"ruimte toe te treden: "
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr "De uitnodiging is geldig tot "
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
"Tandoor Recepten is een Open Source recepten manager. Bekijk het op GitHub "
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr "Tandoor Recepten uitnodiging"
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr "Bestaande boodschappenlijst is bijgewerkt"
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
@ -791,22 +791,22 @@ msgstr ""
|
||||
"Lijst van ingrediënten ID's van het toe te voegen recept, als deze niet "
|
||||
"opgegeven worden worden alle ingrediënten toegevoegd."
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
"Als je een list_recipe ID en portiegrootte van 0 opgeeft wordt dat "
|
||||
"boodschappenlijstje verwijderd."
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr "Hoeveelheid eten om aan het boodschappenlijstje toe te voegen"
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr "ID of eenheid om te gebruik voor het boodschappenlijstje"
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
"Wanneer ingesteld op waar, wordt al het voedsel van actieve "
|
||||
@ -948,7 +948,7 @@ msgstr ""
|
||||
"<a href=\"%(email_url)s\">Vraag een nieuwe bevestigingslink aan</a>."
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Inloggen"
|
||||
|
||||
@ -1120,7 +1120,7 @@ msgstr "Registratie gesloten"
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr "Excuses, registratie is op dit moment gesloten."
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "API documentatie"
|
||||
@ -1215,36 +1215,36 @@ msgstr "Beheer"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Geen ruimte"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr "Markdown gids"
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr "Vertaal Tandoor"
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "API Browser"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr "Uitloggen"
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr "Je gebruikt de gratis versie van Tandoor"
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr "Upgrade nu"
|
||||
|
||||
@ -2365,19 +2365,11 @@ msgstr "Recepten zonder etiketten"
|
||||
msgid "Internal Recipes"
|
||||
msgstr "Interne recepten"
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Uitnodigingslink"
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr "Toon links"
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr "Systeeminformatie"
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2395,21 +2387,21 @@ msgstr ""
|
||||
"recipes/releases\">hier</a> gevonden worden.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr "Media aanbieder"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr "Waarschuwing"
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr "Oké"
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2424,16 +2416,16 @@ msgstr ""
|
||||
"releases/tag/0.8.1\">hier</a> beschreven om je installatie te updaten.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr "Alles is in orde!"
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr "Geheime sleutel"
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2453,11 +2445,11 @@ msgstr ""
|
||||
"configuratiebestand.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr "Debug modus"
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2475,15 +2467,15 @@ msgstr ""
|
||||
"passen.\n"
|
||||
" "
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr "Database"
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2501,76 +2493,76 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr "Importeer URL"
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr "Parameter updatet_at is onjuist geformateerd"
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr "Er bestaat geen {self.basename} met id {pk}"
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr "Kan niet met hetzelfde object samenvoegen!"
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr "Er bestaat geen {self.basename} met id {target}"
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr "Kan niet met kindobject samenvoegen!"
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr "{source.name} is succesvol samengevoegd met {target.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
"Er is een error opgetreden bij het samenvoegen van {source.name} met {target."
|
||||
"name}"
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr "{child.name} is succesvol verplaatst naar het hoogste niveau."
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr "Er is een error opgetreden bij het verplaatsen "
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr "Kan object niet verplaatsen naar zichzelf!"
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr "Er bestaat geen {self.basename} met id {parent}"
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr "{child.name} is succesvol verplaatst naar {parent.name}"
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr "{obj.name} is verwijderd van het boodschappenlijstje."
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr "{obj.name} is toegevoegd aan het boodschappenlijstje."
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"ID van het recept waar de stap onderdeel van is. Herhaal parameter voor "
|
||||
"meerdere."
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr "Zoekterm komt overeen (fuzzy) met object naam."
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
@ -2578,7 +2570,7 @@ msgstr ""
|
||||
"Zoekterm komt overeen (fuzzy) met recept naam. In de toekomst wordt zoeken "
|
||||
"op volledige tekst ondersteund."
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
@ -2586,109 +2578,109 @@ msgstr ""
|
||||
"ID van etiket dat een recept moet hebben. Herhaal parameter voor meerdere. "
|
||||
"Gelijkwaardig aan keywords_or"
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
"Etiket ID, herhaal voor meerdere. Geeft recepten met elk geselecteerd etiket "
|
||||
"weer"
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
"Etiket ID, herhaal voor meerdere. Geeft recepten met alle geselecteerde "
|
||||
"etiketten weer."
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
"Etiket ID, herhaal voor meerdere. Sluit recepten met één van de etiketten "
|
||||
"uit."
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
"Etiket ID, herhaal voor meerdere. Sluit recepten met alle etiketten uit."
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"ID van ingrediënt dat een recept moet hebben. Herhaal parameter voor "
|
||||
"meerdere."
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
"Ingrediënt ID, herhaal voor meerdere. Geeft recepten met elk ingrediënt weer"
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
"Ingrediënt ID, herhaal voor meerdere. Geef recepten met alle ingrediënten "
|
||||
"weer."
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
"Ingrediënt ID, herhaal voor meerdere. sluit recepten met één van de "
|
||||
"ingrediënten uit."
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
"Ingrediënt ID, herhaal voor meerdere. Sluit recepten met alle ingrediënten "
|
||||
"uit."
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr "ID van eenheid dat een recept moet hebben."
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr "Een waardering van een recept gaat van 0 tot 5."
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
"ID van boek dat een recept moet hebben. Herhaal parameter voor meerdere."
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr "Boek ID, herhaal voor meerdere. Geeft recepten uit alle boeken weer"
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr "Boek IDs, herhaal voor meerdere. Geeft recepten weer uit alle boeken."
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
"Boek IDs, herhaal voor meerdere. Sluit recepten uit elk van de boeken uit."
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr "Boek IDs, herhaal voor meerdere. Sluit recepten uit alle boeken uit."
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
"Wanneer alleen interne recepten gevonden moeten worden. [waar/<b>onwaar</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
"Geeft de resultaten in willekeurige volgorde weer. [waar/<b>onwaar</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr "Geeft nieuwe resultaten eerst weer. [waar/<b>onwaar</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
@ -2696,7 +2688,7 @@ msgstr ""
|
||||
"Filter recepten X maal of meer bereid. Negatieve waarden geven minder dan X "
|
||||
"keer bereide recepten weer"
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
@ -2704,7 +2696,7 @@ msgstr ""
|
||||
"Filter recepten op laatst bereid op of na JJJJ-MM-DD. Voorafgaand - filters "
|
||||
"op of voor datum."
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
@ -2712,7 +2704,7 @@ msgstr ""
|
||||
"Filter recepten aangemaakt op of na JJJJ-MM-DD. Voorafgaand - filters op of "
|
||||
"voor datum."
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
@ -2720,7 +2712,7 @@ msgstr ""
|
||||
"Filter recepten op geüpdatet op of na JJJJ-MM-DD. Voorafgaand - filters op "
|
||||
"of voor datum."
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
@ -2728,13 +2720,13 @@ msgstr ""
|
||||
"Filter recepten op laatst bekeken op of na JJJJ-MM-DD. Voorafgaand - filters "
|
||||
"op of voor datum."
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
"Filter recepten die bereid kunnen worden met ingrediënten die op voorraad "
|
||||
"zijn. [waar/<b>onwaar</b>]"
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
@ -2742,7 +2734,7 @@ msgstr ""
|
||||
"Geeft het boodschappenlijstje item met een primaire sleutel van id. "
|
||||
"Meerdere waarden toegestaan."
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
@ -2750,41 +2742,41 @@ msgstr ""
|
||||
"Filter boodschappenlijstjes op aangevinkt. [waar,onwaar,beide,<b>recent</b>]"
|
||||
"<br> - recent bevat niet aangevinkte en recent voltooide items."
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
"Geeft items op boodschappenlijstjes gesorteerd per supermarktcategorie weer."
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr "Niks te doen."
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr "Verbinding geweigerd."
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr "Verkeerd URL schema."
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
msgid "No usable data could be found."
|
||||
msgstr "Er is geen bruikbare data gevonden."
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr "Deze optie is nog niet beschikbaar in de gehoste versie van Tandoor!"
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr "Synchronisatie succesvol!"
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr "Er is een fout opgetreden bij het synchroniseren met Opslag"
|
||||
|
||||
@ -2873,6 +2865,10 @@ msgstr "Ontdekken"
|
||||
msgid "Shopping List"
|
||||
msgstr "Boodschappenlijst"
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr "Uitnodigingslink"
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr "Supermarkten"
|
||||
@ -2980,6 +2976,9 @@ msgstr ""
|
||||
"Links voor het delen van recepten zijn gedeactiveerd. Neem contact op met de "
|
||||
"paginabeheerder voor aanvullende informatie."
|
||||
|
||||
#~ msgid "Show Links"
|
||||
#~ msgstr "Toon links"
|
||||
|
||||
#~ msgid "A user is required"
|
||||
#~ msgstr "Een gebruiker is verplicht"
|
||||
|
||||
|
@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2021-11-12 20:06+0000\n"
|
||||
"Last-Translator: Henrique Silva <hds@mailbox.org>\n"
|
||||
"Language-Team: Portuguese <http://translate.tandoor.dev/projects/tandoor/"
|
||||
@ -529,7 +529,7 @@ msgstr ""
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -544,12 +544,12 @@ msgstr "É necessário inserir uma receita ou um título."
|
||||
msgid "Could not parse template code."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
#, fuzzy
|
||||
@ -685,127 +685,127 @@ msgstr "Novo"
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "New Food"
|
||||
msgid "Food Alias"
|
||||
msgstr "Novo Prato"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Units"
|
||||
msgid "Unit Alias"
|
||||
msgstr "Unidades"
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
#, fuzzy
|
||||
#| msgid "Keywords"
|
||||
msgid "Keyword Alias"
|
||||
msgstr "Palavras-chave"
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr "Receita"
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
#, fuzzy
|
||||
#| msgid "New Food"
|
||||
msgid "Food"
|
||||
msgstr "Novo Prato"
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr "Palavra-chave"
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -939,7 +939,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr "Iniciar sessão"
|
||||
|
||||
@ -1107,7 +1107,7 @@ msgstr ""
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr "Documentação API"
|
||||
@ -1212,36 +1212,36 @@ msgstr "Administração"
|
||||
msgid "Your Spaces"
|
||||
msgstr "Criar"
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr "GitHub"
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr "Navegador de API"
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2241,19 +2241,11 @@ msgstr ""
|
||||
msgid "Internal Recipes"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2264,21 +2256,21 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2288,16 +2280,16 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2310,11 +2302,11 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2325,15 +2317,15 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2346,245 +2338,245 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
msgid "No usable data could be found."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr ""
|
||||
|
||||
@ -2667,6 +2659,10 @@ msgstr ""
|
||||
msgid "Shopping List"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr ""
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -471,7 +471,7 @@ msgstr ""
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -484,12 +484,12 @@ msgstr ""
|
||||
msgid "Could not parse template code."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -620,119 +620,119 @@ msgstr ""
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
msgid "Food"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -864,7 +864,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
@ -1028,7 +1028,7 @@ msgstr ""
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr ""
|
||||
@ -1121,36 +1121,36 @@ msgstr ""
|
||||
msgid "Your Spaces"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2091,19 +2091,11 @@ msgstr ""
|
||||
msgid "Internal Recipes"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2114,21 +2106,21 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2138,16 +2130,16 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2160,11 +2152,11 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2175,15 +2167,15 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2196,245 +2188,245 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
msgid "No usable data could be found."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr ""
|
||||
|
||||
@ -2517,6 +2509,10 @@ msgstr ""
|
||||
msgid "Shopping List"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr ""
|
||||
|
@ -11,7 +11,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: 2020-06-02 19:28+0000\n"
|
||||
"Last-Translator: Emre S, 2020\n"
|
||||
"Language-Team: Turkish (https://www.transifex.com/django-recipes/"
|
||||
@ -488,7 +488,7 @@ msgstr ""
|
||||
msgid "You have more users than allowed in your space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\helper\recipe_search.py:560
|
||||
#: .\cookbook\helper\recipe_search.py:565
|
||||
msgid "One of queryset or hash_key must be provided"
|
||||
msgstr ""
|
||||
|
||||
@ -501,12 +501,12 @@ msgstr ""
|
||||
msgid "Could not parse template code."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:42
|
||||
#: .\cookbook\integration\copymethat.py:41
|
||||
#: .\cookbook\integration\melarecipes.py:37
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\integration\copymethat.py:71
|
||||
#: .\cookbook\integration\copymethat.py:70
|
||||
#: .\cookbook\integration\recettetek.py:54
|
||||
#: .\cookbook\integration\recipekeeper.py:63
|
||||
msgid "Imported from"
|
||||
@ -637,119 +637,119 @@ msgstr ""
|
||||
msgid " is part of a recipe step and cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1160 .\cookbook\templates\search_info.html:28
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:28
|
||||
msgid "Simple"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1161 .\cookbook\templates\search_info.html:33
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:33
|
||||
msgid "Phrase"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1162 .\cookbook\templates\search_info.html:38
|
||||
#: .\cookbook\models.py:1164 .\cookbook\templates\search_info.html:38
|
||||
msgid "Web"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1163 .\cookbook\templates\search_info.html:47
|
||||
#: .\cookbook\models.py:1165 .\cookbook\templates\search_info.html:47
|
||||
msgid "Raw"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Food Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Unit Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1201
|
||||
#: .\cookbook\models.py:1203
|
||||
msgid "Keyword Alias"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1225
|
||||
#: .\cookbook\models.py:1227
|
||||
#: .\cookbook\templates\include\recipe_open_modal.html:7
|
||||
#: .\cookbook\views\delete.py:36 .\cookbook\views\edit.py:251
|
||||
#: .\cookbook\views\new.py:48
|
||||
msgid "Recipe"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1226
|
||||
#: .\cookbook\models.py:1228
|
||||
msgid "Food"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\models.py:1227 .\cookbook\templates\base.html:138
|
||||
#: .\cookbook\models.py:1229 .\cookbook\templates\base.html:138
|
||||
msgid "Keyword"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:204
|
||||
#: .\cookbook\serializer.py:207
|
||||
msgid "Cannot modify Space owner permission."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:273
|
||||
#: .\cookbook\serializer.py:290
|
||||
msgid "File uploads are not enabled for this Space."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:284
|
||||
#: .\cookbook\serializer.py:301
|
||||
msgid "You have reached your file upload limit."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "Hello"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1051
|
||||
#: .\cookbook\serializer.py:1081
|
||||
msgid "You have been invited by "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1052
|
||||
#: .\cookbook\serializer.py:1082
|
||||
msgid " to join their Tandoor Recipes space "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1053
|
||||
#: .\cookbook\serializer.py:1083
|
||||
msgid "Click the following link to activate your account: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1054
|
||||
#: .\cookbook\serializer.py:1084
|
||||
msgid ""
|
||||
"If the link does not work use the following code to manually join the space: "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1055
|
||||
#: .\cookbook\serializer.py:1085
|
||||
msgid "The invitation is valid until "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1056
|
||||
#: .\cookbook\serializer.py:1086
|
||||
msgid ""
|
||||
"Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1059
|
||||
#: .\cookbook\serializer.py:1089
|
||||
msgid "Tandoor Recipes Invite"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1179
|
||||
#: .\cookbook\serializer.py:1209
|
||||
msgid "Existing shopping list to update"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1181
|
||||
#: .\cookbook\serializer.py:1211
|
||||
msgid ""
|
||||
"List of ingredient IDs from the recipe to add, if not provided all "
|
||||
"ingredients will be added."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1183
|
||||
#: .\cookbook\serializer.py:1213
|
||||
msgid ""
|
||||
"Providing a list_recipe ID and servings of 0 will delete that shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1192
|
||||
#: .\cookbook\serializer.py:1222
|
||||
msgid "Amount of food to add to the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1194
|
||||
#: .\cookbook\serializer.py:1224
|
||||
msgid "ID of unit to use for the shopping list"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\serializer.py:1196
|
||||
#: .\cookbook\serializer.py:1226
|
||||
msgid "When set to true will delete all food from active shopping lists."
|
||||
msgstr ""
|
||||
|
||||
@ -881,7 +881,7 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\account\login.html:8
|
||||
#: .\cookbook\templates\base.html:339 .\cookbook\templates\openid\login.html:8
|
||||
#: .\cookbook\templates\base.html:340 .\cookbook\templates\openid\login.html:8
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
@ -1045,7 +1045,7 @@ msgstr ""
|
||||
msgid "We are sorry, but the sign up is currently closed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:329
|
||||
#: .\cookbook\templates\api_info.html:5 .\cookbook\templates\base.html:330
|
||||
#: .\cookbook\templates\rest_framework\api.html:11
|
||||
msgid "API Documentation"
|
||||
msgstr ""
|
||||
@ -1140,36 +1140,36 @@ msgstr ""
|
||||
msgid "Your Spaces"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:319
|
||||
#: .\cookbook\templates\base.html:320
|
||||
#: .\cookbook\templates\space_overview.html:6
|
||||
msgid "Overview"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:323
|
||||
#: .\cookbook\templates\base.html:324
|
||||
msgid "Markdown Guide"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:325
|
||||
#: .\cookbook\templates\base.html:326
|
||||
msgid "GitHub"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:327
|
||||
#: .\cookbook\templates\base.html:328
|
||||
msgid "Translate Tandoor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:331
|
||||
#: .\cookbook\templates\base.html:332
|
||||
msgid "API Browser"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:334
|
||||
#: .\cookbook\templates\base.html:335
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:356
|
||||
#: .\cookbook\templates\base.html:357
|
||||
msgid "You are using the free version of Tandor"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\base.html:357
|
||||
#: .\cookbook\templates\base.html:358
|
||||
msgid "Upgrade Now"
|
||||
msgstr ""
|
||||
|
||||
@ -2110,19 +2110,11 @@ msgstr ""
|
||||
msgid "Internal Recipes"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:21 .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid "Show Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:32
|
||||
#: .\cookbook\templates\system.html:20
|
||||
msgid "System Information"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:34
|
||||
#: .\cookbook\templates\system.html:22
|
||||
msgid ""
|
||||
"\n"
|
||||
" Django Recipes is an open source free software application. It can "
|
||||
@ -2133,21 +2125,21 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:48
|
||||
#: .\cookbook\templates\system.html:36
|
||||
msgid "Media Serving"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68
|
||||
msgid "Warning"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:49 .\cookbook\templates\system.html:64
|
||||
#: .\cookbook\templates\system.html:80 .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:37 .\cookbook\templates\system.html:52
|
||||
#: .\cookbook\templates\system.html:68 .\cookbook\templates\system.html:83
|
||||
msgid "Ok"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:51
|
||||
#: .\cookbook\templates\system.html:39
|
||||
msgid ""
|
||||
"Serving media files directly using gunicorn/python is <b>not recommend</b>!\n"
|
||||
" Please follow the steps described\n"
|
||||
@ -2157,16 +2149,16 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:57 .\cookbook\templates\system.html:73
|
||||
#: .\cookbook\templates\system.html:88 .\cookbook\templates\system.html:102
|
||||
#: .\cookbook\templates\system.html:45 .\cookbook\templates\system.html:61
|
||||
#: .\cookbook\templates\system.html:76 .\cookbook\templates\system.html:90
|
||||
msgid "Everything is fine!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:62
|
||||
#: .\cookbook\templates\system.html:50
|
||||
msgid "Secret Key"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:66
|
||||
#: .\cookbook\templates\system.html:54
|
||||
msgid ""
|
||||
"\n"
|
||||
" You do not have a <code>SECRET_KEY</code> configured in your "
|
||||
@ -2179,11 +2171,11 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:78
|
||||
#: .\cookbook\templates\system.html:66
|
||||
msgid "Debug Mode"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:82
|
||||
#: .\cookbook\templates\system.html:70
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is still running in debug mode. This is most "
|
||||
@ -2194,15 +2186,15 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:93
|
||||
#: .\cookbook\templates\system.html:81
|
||||
msgid "Database"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:95
|
||||
#: .\cookbook\templates\system.html:83
|
||||
msgid "Info"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\templates\system.html:97
|
||||
#: .\cookbook\templates\system.html:85
|
||||
msgid ""
|
||||
"\n"
|
||||
" This application is not running with a Postgres database "
|
||||
@ -2215,245 +2207,245 @@ msgstr ""
|
||||
msgid "URL Import"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:97 .\cookbook\views\api.py:189
|
||||
#: .\cookbook\views\api.py:105 .\cookbook\views\api.py:197
|
||||
msgid "Parameter updated_at incorrectly formatted"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:209 .\cookbook\views\api.py:312
|
||||
#: .\cookbook\views\api.py:217 .\cookbook\views\api.py:320
|
||||
msgid "No {self.basename} with id {pk} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:213
|
||||
#: .\cookbook\views\api.py:221
|
||||
msgid "Cannot merge with the same object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:220
|
||||
#: .\cookbook\views\api.py:228
|
||||
msgid "No {self.basename} with id {target} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:225
|
||||
#: .\cookbook\views\api.py:233
|
||||
msgid "Cannot merge with child object!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:258
|
||||
#: .\cookbook\views\api.py:266
|
||||
msgid "{source.name} was merged successfully with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:263
|
||||
#: .\cookbook\views\api.py:271
|
||||
msgid "An error occurred attempting to merge {source.name} with {target.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:321
|
||||
#: .\cookbook\views\api.py:329
|
||||
msgid "{child.name} was moved successfully to the root."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:324 .\cookbook\views\api.py:342
|
||||
#: .\cookbook\views\api.py:332 .\cookbook\views\api.py:350
|
||||
msgid "An error occurred attempting to move "
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:327
|
||||
#: .\cookbook\views\api.py:335
|
||||
msgid "Cannot move an object to itself!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:333
|
||||
#: .\cookbook\views\api.py:341
|
||||
msgid "No {self.basename} with id {parent} exists"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:339
|
||||
#: .\cookbook\views\api.py:347
|
||||
msgid "{child.name} was moved successfully to parent {parent.name}"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:534
|
||||
#: .\cookbook\views\api.py:542
|
||||
msgid "{obj.name} was removed from the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:539 .\cookbook\views\api.py:871
|
||||
#: .\cookbook\views\api.py:884
|
||||
#: .\cookbook\views\api.py:547 .\cookbook\views\api.py:879
|
||||
#: .\cookbook\views\api.py:892
|
||||
msgid "{obj.name} was added to the shopping list."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:666
|
||||
#: .\cookbook\views\api.py:674
|
||||
msgid "ID of recipe a step is part of. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:668
|
||||
#: .\cookbook\views\api.py:676
|
||||
msgid "Query string matched (fuzzy) against object name."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:712
|
||||
#: .\cookbook\views\api.py:720
|
||||
msgid ""
|
||||
"Query string matched (fuzzy) against recipe name. In the future also "
|
||||
"fulltext search."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:714
|
||||
#: .\cookbook\views\api.py:722
|
||||
msgid ""
|
||||
"ID of keyword a recipe should have. For multiple repeat parameter. "
|
||||
"Equivalent to keywords_or"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:717
|
||||
#: .\cookbook\views\api.py:725
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with any of the keywords"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:720
|
||||
#: .\cookbook\views\api.py:728
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Return recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:723
|
||||
#: .\cookbook\views\api.py:731
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with any of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:726
|
||||
#: .\cookbook\views\api.py:734
|
||||
msgid ""
|
||||
"Keyword IDs, repeat for multiple. Exclude recipes with all of the keywords."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:728
|
||||
#: .\cookbook\views\api.py:736
|
||||
msgid "ID of food a recipe should have. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:731
|
||||
#: .\cookbook\views\api.py:739
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with any of the foods"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:733
|
||||
#: .\cookbook\views\api.py:741
|
||||
msgid "Food IDs, repeat for multiple. Return recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:735
|
||||
#: .\cookbook\views\api.py:743
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with any of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:737
|
||||
#: .\cookbook\views\api.py:745
|
||||
msgid "Food IDs, repeat for multiple. Exclude recipes with all of the foods."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:738
|
||||
#: .\cookbook\views\api.py:746
|
||||
msgid "ID of unit a recipe should have."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:740
|
||||
#: .\cookbook\views\api.py:748
|
||||
msgid ""
|
||||
"Rating a recipe should have or greater. [0 - 5] Negative value filters "
|
||||
"rating less than."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:741
|
||||
#: .\cookbook\views\api.py:749
|
||||
msgid "ID of book a recipe should be in. For multiple repeat parameter."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:743
|
||||
#: .\cookbook\views\api.py:751
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with any of the books"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:745
|
||||
#: .\cookbook\views\api.py:753
|
||||
msgid "Book IDs, repeat for multiple. Return recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:747
|
||||
#: .\cookbook\views\api.py:755
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with any of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:749
|
||||
#: .\cookbook\views\api.py:757
|
||||
msgid "Book IDs, repeat for multiple. Exclude recipes with all of the books."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:751
|
||||
#: .\cookbook\views\api.py:759
|
||||
msgid "If only internal recipes should be returned. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:753
|
||||
#: .\cookbook\views\api.py:761
|
||||
msgid "Returns the results in randomized order. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:755
|
||||
#: .\cookbook\views\api.py:763
|
||||
msgid "Returns new results first in search results. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:757
|
||||
#: .\cookbook\views\api.py:765
|
||||
msgid ""
|
||||
"Filter recipes cooked X times or more. Negative values returns cooked less "
|
||||
"than X times"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:759
|
||||
#: .\cookbook\views\api.py:767
|
||||
msgid ""
|
||||
"Filter recipes last cooked on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:761
|
||||
#: .\cookbook\views\api.py:769
|
||||
msgid ""
|
||||
"Filter recipes created on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:763
|
||||
#: .\cookbook\views\api.py:771
|
||||
msgid ""
|
||||
"Filter recipes updated on or after YYYY-MM-DD. Prepending - filters on or "
|
||||
"before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:765
|
||||
#: .\cookbook\views\api.py:773
|
||||
msgid ""
|
||||
"Filter recipes lasts viewed on or after YYYY-MM-DD. Prepending - filters on "
|
||||
"or before date."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:767
|
||||
#: .\cookbook\views\api.py:775
|
||||
msgid "Filter recipes that can be made with OnHand food. [true/<b>false</b>]"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:929
|
||||
#: .\cookbook\views\api.py:937
|
||||
msgid ""
|
||||
"Returns the shopping list entry with a primary key of id. Multiple values "
|
||||
"allowed."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:934
|
||||
#: .\cookbook\views\api.py:942
|
||||
msgid ""
|
||||
"Filter shopping list entries on checked. [true, false, both, <b>recent</b>]"
|
||||
"<br> - recent includes unchecked items and recently completed items."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:937
|
||||
#: .\cookbook\views\api.py:945
|
||||
msgid "Returns the shopping list entries sorted by supermarket category order."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1134
|
||||
#: .\cookbook\views\api.py:1140
|
||||
msgid "Nothing to do."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1153
|
||||
#: .\cookbook\views\api.py:1160
|
||||
msgid "Invalid Url"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1158
|
||||
#: .\cookbook\views\api.py:1167
|
||||
msgid "Connection Refused."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1163
|
||||
#: .\cookbook\views\api.py:1172
|
||||
msgid "Bad URL Schema."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1170
|
||||
#: .\cookbook\views\api.py:1195
|
||||
msgid "No usable data could be found."
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1260 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\api.py:1303 .\cookbook\views\data.py:28
|
||||
#: .\cookbook\views\edit.py:120 .\cookbook\views\new.py:90
|
||||
msgid "This feature is not yet available in the hosted version of tandoor!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1282
|
||||
#: .\cookbook\views\api.py:1325
|
||||
msgid "Sync successful!"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\api.py:1287
|
||||
#: .\cookbook\views\api.py:1330
|
||||
msgid "Error synchronizing with Storage"
|
||||
msgstr ""
|
||||
|
||||
@ -2536,6 +2528,10 @@ msgstr ""
|
||||
msgid "Shopping List"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:76
|
||||
msgid "Invite Links"
|
||||
msgstr ""
|
||||
|
||||
#: .\cookbook\views\lists.py:139
|
||||
msgid "Supermarkets"
|
||||
msgstr ""
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-12 18:04
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0177_recipe_show_ingredient_overview'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='userpreference',
|
||||
name='search_style',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='userpreference',
|
||||
name='show_recent',
|
||||
),
|
||||
]
|
25
cookbook/migrations/0179_recipe_private_recipe_shared.py
Normal file
25
cookbook/migrations/0179_recipe_private_recipe_shared.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-13 10:53
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('cookbook', '0178_remove_userpreference_search_style_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='recipe',
|
||||
name='private',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='recipe',
|
||||
name='shared',
|
||||
field=models.ManyToManyField(blank=True, related_name='recipe_shared_with', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
18
cookbook/migrations/0180_invitelink_reusable.py
Normal file
18
cookbook/migrations/0180_invitelink_reusable.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-14 09:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0179_recipe_private_recipe_shared'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='invitelink',
|
||||
name='reusable',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
19
cookbook/migrations/0181_space_image.py
Normal file
19
cookbook/migrations/0181_space_image.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-14 11:14
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0180_invitelink_reusable'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='space',
|
||||
name='image',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_image', to='cookbook.userfile'),
|
||||
),
|
||||
]
|
19
cookbook/migrations/0182_userpreference_image.py
Normal file
19
cookbook/migrations/0182_userpreference_image.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.0.6 on 2022-07-14 13:32
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0181_space_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userpreference',
|
||||
name='image',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='user_image', to='cookbook.userfile'),
|
||||
),
|
||||
]
|
19
cookbook/migrations/0183_alter_space_image.py
Normal file
19
cookbook/migrations/0183_alter_space_image.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.0.6 on 2022-08-04 16:46
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cookbook', '0182_userpreference_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='space',
|
||||
name='image',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_image', to='cookbook.userfile'),
|
||||
),
|
||||
]
|
@ -4,6 +4,8 @@ import re
|
||||
import uuid
|
||||
from datetime import date, timedelta
|
||||
|
||||
import oauth2_provider.models
|
||||
from PIL import Image
|
||||
from annoying.fields import AutoOneToOneField
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth.models import Group, User
|
||||
@ -25,7 +27,7 @@ from recipes.settings import (COMMENT_PREF_DEFAULT, FRACTION_PREF_DEFAULT, KJ_PR
|
||||
SORT_TREE_BY_NAME, STICKY_NAV_PREF_DEFAULT)
|
||||
|
||||
|
||||
def get_user_name(self):
|
||||
def get_user_display_name(self):
|
||||
if not (name := f"{self.first_name} {self.last_name}") == " ":
|
||||
return name
|
||||
else:
|
||||
@ -57,11 +59,18 @@ def get_shopping_share(self):
|
||||
]))
|
||||
|
||||
|
||||
auth.models.User.add_to_class('get_user_name', get_user_name)
|
||||
auth.models.User.add_to_class('get_user_display_name', get_user_display_name)
|
||||
auth.models.User.add_to_class('get_shopping_share', get_shopping_share)
|
||||
auth.models.User.add_to_class('get_active_space', get_active_space)
|
||||
|
||||
|
||||
def oauth_token_get_owner(self):
|
||||
return self.user
|
||||
|
||||
|
||||
oauth2_provider.models.AccessToken.add_to_class('get_owner', oauth_token_get_owner)
|
||||
|
||||
|
||||
def get_model_name(model):
|
||||
return ('_'.join(re.findall('[A-Z][^A-Z]*', model.__name__))).lower()
|
||||
|
||||
@ -244,6 +253,7 @@ class FoodInheritField(models.Model, PermissionModelMixin):
|
||||
|
||||
class Space(ExportModelOperationsMixin('space'), models.Model):
|
||||
name = models.CharField(max_length=128, default='Default')
|
||||
image = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, blank=True, related_name='space_image')
|
||||
created_by = models.ForeignKey(User, on_delete=models.PROTECT, null=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
message = models.CharField(max_length=512, default='', blank=True)
|
||||
@ -355,34 +365,16 @@ class UserPreference(models.Model, PermissionModelMixin):
|
||||
(BOOKS, _('Books')),
|
||||
)
|
||||
|
||||
# Search Style
|
||||
SMALL = 'SMALL'
|
||||
LARGE = 'LARGE'
|
||||
NEW = 'NEW'
|
||||
|
||||
SEARCH_STYLE = ((SMALL, _('Small')), (LARGE, _('Large')), (NEW, _('New')))
|
||||
|
||||
user = AutoOneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
||||
image = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, related_name='user_image')
|
||||
theme = models.CharField(choices=THEMES, max_length=128, default=TANDOOR)
|
||||
nav_color = models.CharField(
|
||||
choices=COLORS, max_length=128, default=PRIMARY
|
||||
)
|
||||
nav_color = models.CharField(choices=COLORS, max_length=128, default=PRIMARY)
|
||||
default_unit = models.CharField(max_length=32, default='g')
|
||||
use_fractions = models.BooleanField(default=FRACTION_PREF_DEFAULT)
|
||||
use_kj = models.BooleanField(default=KJ_PREF_DEFAULT)
|
||||
default_page = models.CharField(
|
||||
choices=PAGES, max_length=64, default=SEARCH
|
||||
)
|
||||
search_style = models.CharField(
|
||||
choices=SEARCH_STYLE, max_length=64, default=NEW
|
||||
)
|
||||
show_recent = models.BooleanField(default=True)
|
||||
plan_share = models.ManyToManyField(
|
||||
User, blank=True, related_name='plan_share_default'
|
||||
)
|
||||
shopping_share = models.ManyToManyField(
|
||||
User, blank=True, related_name='shopping_share'
|
||||
)
|
||||
default_page = models.CharField(choices=PAGES, max_length=64, default=SEARCH)
|
||||
plan_share = models.ManyToManyField(User, blank=True, related_name='plan_share_default')
|
||||
shopping_share = models.ManyToManyField(User, blank=True, related_name='shopping_share')
|
||||
ingredient_decimals = models.IntegerField(default=2)
|
||||
comments = models.BooleanField(default=COMMENT_PREF_DEFAULT)
|
||||
shopping_auto_sync = models.IntegerField(default=5)
|
||||
@ -612,7 +604,7 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
|
||||
# remove all inherited fields from food
|
||||
trough = Food.inherit_fields.through
|
||||
trough.objects.all().delete()
|
||||
|
||||
|
||||
# food is going to inherit attributes
|
||||
if len(inherit) > 0:
|
||||
# ManyToMany cannot be updated through an UPDATE operation
|
||||
@ -749,6 +741,8 @@ class Recipe(ExportModelOperationsMixin('recipe'), models.Model, PermissionModel
|
||||
internal = models.BooleanField(default=False)
|
||||
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
|
||||
show_ingredient_overview = models.BooleanField(default=True)
|
||||
private = models.BooleanField(default=False)
|
||||
shared = models.ManyToManyField(User, blank=True, related_name='recipe_shared_with')
|
||||
|
||||
source_url = models.CharField(max_length=1024, default=None, blank=True, null=True)
|
||||
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
|
||||
@ -1017,9 +1011,8 @@ class InviteLink(ExportModelOperationsMixin('invite_link'), models.Model, Permis
|
||||
email = models.EmailField(blank=True)
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
valid_until = models.DateField(default=default_valid_until)
|
||||
used_by = models.ForeignKey(
|
||||
User, null=True, on_delete=models.CASCADE, related_name='used_by'
|
||||
)
|
||||
used_by = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name='used_by')
|
||||
reusable = models.BooleanField(default=False)
|
||||
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@ -1187,6 +1180,13 @@ class UserFile(ExportModelOperationsMixin('user_files'), models.Model, Permissio
|
||||
objects = ScopedManager(space='space')
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE)
|
||||
|
||||
def is_image(self):
|
||||
try:
|
||||
img = Image.open(self.file.file.file)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if hasattr(self.file, 'file') and isinstance(self.file.file, UploadedFile) or isinstance(self.file.file, InMemoryUploadedFile):
|
||||
self.file.name = f'{uuid.uuid4()}' + pathlib.Path(self.file.name).suffix
|
||||
|
@ -1,12 +1,12 @@
|
||||
import traceback
|
||||
from datetime import timedelta, datetime
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from gettext import gettext as _
|
||||
from html import escape
|
||||
from smtplib import SMTPException
|
||||
|
||||
from PIL import Image
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.contrib.auth.models import Group, User, AnonymousUser
|
||||
from django.core.mail import send_mail
|
||||
from django.db.models import Avg, Q, QuerySet, Sum
|
||||
from django.http import BadHeaderError
|
||||
@ -14,6 +14,8 @@ from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django_scopes import scopes_disabled
|
||||
from drf_writable_nested import UniqueFieldsMixin, WritableNestedModelSerializer
|
||||
from PIL import Image
|
||||
from oauth2_provider.models import AccessToken
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import NotFound, ValidationError
|
||||
|
||||
@ -22,14 +24,14 @@ 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,
|
||||
MealPlan, MealType, NutritionInformation, Recipe, RecipeBook,
|
||||
ExportLog, Food, FoodInheritField, ImportLog, Ingredient, InviteLink,
|
||||
Keyword, MealPlan, MealType, NutritionInformation, Recipe, RecipeBook,
|
||||
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
|
||||
ShoppingListEntry, ShoppingListRecipe, Step, Storage, Supermarket,
|
||||
SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit,
|
||||
UserFile, UserPreference, ViewLog, Space, UserSpace, InviteLink)
|
||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog)
|
||||
from cookbook.templatetags.custom_tags import markdown
|
||||
from recipes.settings import MEDIA_URL, AWS_ENABLED
|
||||
from recipes.settings import AWS_ENABLED, MEDIA_URL
|
||||
|
||||
|
||||
class ExtendedRecipeMixin(serializers.ModelSerializer):
|
||||
@ -124,22 +126,26 @@ class SpaceFilterSerializer(serializers.ListSerializer):
|
||||
# if query is sliced it came from api request not nested serializer
|
||||
return super().to_representation(data)
|
||||
if self.child.Meta.model == User:
|
||||
data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all()
|
||||
if type(self.context['request'].user) == AnonymousUser:
|
||||
data = []
|
||||
else:
|
||||
data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all()
|
||||
else:
|
||||
data = data.filter(**{'__'.join(data.model.get_space_key()): self.context['request'].space})
|
||||
return super().to_representation(data)
|
||||
|
||||
|
||||
class UserNameSerializer(WritableNestedModelSerializer):
|
||||
username = serializers.SerializerMethodField('get_user_label')
|
||||
class UserSerializer(WritableNestedModelSerializer):
|
||||
display_name = serializers.SerializerMethodField('get_user_label')
|
||||
|
||||
def get_user_label(self, obj):
|
||||
return obj.get_user_name()
|
||||
return obj.get_user_display_name()
|
||||
|
||||
class Meta:
|
||||
list_serializer_class = SpaceFilterSerializer
|
||||
model = User
|
||||
fields = ('id', 'username')
|
||||
fields = ('id', 'username', 'first_name', 'last_name', 'display_name')
|
||||
read_only_fields = ('username',)
|
||||
|
||||
|
||||
class GroupSerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
|
||||
@ -170,103 +176,6 @@ class FoodInheritFieldSerializer(UniqueFieldsMixin, WritableNestedModelSerialize
|
||||
read_only_fields = ['id']
|
||||
|
||||
|
||||
class SpaceSerializer(WritableNestedModelSerializer):
|
||||
user_count = serializers.SerializerMethodField('get_user_count')
|
||||
recipe_count = serializers.SerializerMethodField('get_recipe_count')
|
||||
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
|
||||
food_inherit = FoodInheritFieldSerializer(many=True)
|
||||
|
||||
def get_user_count(self, obj):
|
||||
return UserSpace.objects.filter(space=obj).count()
|
||||
|
||||
def get_recipe_count(self, obj):
|
||||
return Recipe.objects.filter(space=obj).count()
|
||||
|
||||
def get_file_size_mb(self, obj):
|
||||
try:
|
||||
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
|
||||
except TypeError:
|
||||
return 0
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
|
||||
class Meta:
|
||||
model = Space
|
||||
fields = ('id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb',)
|
||||
read_only_fields = ('id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo',)
|
||||
|
||||
|
||||
class UserSpaceSerializer(WritableNestedModelSerializer):
|
||||
user = UserNameSerializer(read_only=True)
|
||||
groups = GroupSerializer(many=True)
|
||||
|
||||
def validate(self, data):
|
||||
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
|
||||
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
|
||||
return super().validate(data)
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
|
||||
class Meta:
|
||||
model = UserSpace
|
||||
fields = ('id', 'user', 'space', 'groups', 'active', 'created_at', 'updated_at',)
|
||||
read_only_fields = ('id', 'created_at', 'updated_at', 'space')
|
||||
|
||||
|
||||
class SpacedModelSerializer(serializers.ModelSerializer):
|
||||
def create(self, validated_data):
|
||||
validated_data['space'] = self.context['request'].space
|
||||
return super().create(validated_data)
|
||||
|
||||
|
||||
class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['created_by'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
class Meta:
|
||||
list_serializer_class = SpaceFilterSerializer
|
||||
model = MealType
|
||||
fields = ('id', 'name', 'order', 'icon', 'color', 'default', 'created_by')
|
||||
read_only_fields = ('created_by',)
|
||||
|
||||
|
||||
class UserPreferenceSerializer(WritableNestedModelSerializer):
|
||||
food_inherit_default = serializers.SerializerMethodField('get_food_inherit_defaults')
|
||||
plan_share = UserNameSerializer(many=True, allow_null=True, required=False)
|
||||
shopping_share = UserNameSerializer(many=True, allow_null=True, required=False)
|
||||
food_children_exist = serializers.SerializerMethodField('get_food_children_exist')
|
||||
|
||||
def get_food_inherit_defaults(self, obj):
|
||||
return FoodInheritFieldSerializer(obj.user.get_active_space().food_inherit.all(), many=True).data
|
||||
|
||||
def get_food_children_exist(self, obj):
|
||||
space = getattr(self.context.get('request', None), 'space', None)
|
||||
return Food.objects.filter(depth__gt=0, space=space).exists()
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
with scopes_disabled():
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
|
||||
class Meta:
|
||||
model = UserPreference
|
||||
fields = (
|
||||
'user', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj', 'search_style',
|
||||
'show_recent', 'plan_share',
|
||||
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping',
|
||||
'food_inherit_default', 'default_delay',
|
||||
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days',
|
||||
'csv_delim', 'csv_prefix',
|
||||
'filter_to_supermarket', 'shopping_add_onhand', 'left_handed', 'food_children_exist'
|
||||
)
|
||||
|
||||
|
||||
class UserFileSerializer(serializers.ModelSerializer):
|
||||
file = serializers.FileField(write_only=True)
|
||||
file_download = serializers.SerializerMethodField('get_download_link')
|
||||
@ -343,6 +252,106 @@ class UserFileViewSerializer(serializers.ModelSerializer):
|
||||
read_only_fields = ('id', 'file')
|
||||
|
||||
|
||||
class SpaceSerializer(WritableNestedModelSerializer):
|
||||
user_count = serializers.SerializerMethodField('get_user_count')
|
||||
recipe_count = serializers.SerializerMethodField('get_recipe_count')
|
||||
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
|
||||
food_inherit = FoodInheritFieldSerializer(many=True)
|
||||
image = UserFileViewSerializer(required=False, many=False, allow_null=True)
|
||||
|
||||
def get_user_count(self, obj):
|
||||
return UserSpace.objects.filter(space=obj).count()
|
||||
|
||||
def get_recipe_count(self, obj):
|
||||
return Recipe.objects.filter(space=obj).count()
|
||||
|
||||
def get_file_size_mb(self, obj):
|
||||
try:
|
||||
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
|
||||
except TypeError:
|
||||
return 0
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
|
||||
class Meta:
|
||||
model = Space
|
||||
fields = ('id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
|
||||
'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb', 'image',)
|
||||
read_only_fields = ('id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo',)
|
||||
|
||||
|
||||
class UserSpaceSerializer(WritableNestedModelSerializer):
|
||||
user = UserSerializer(read_only=True)
|
||||
groups = GroupSerializer(many=True)
|
||||
|
||||
def validate(self, data):
|
||||
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
|
||||
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
|
||||
return super().validate(data)
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
|
||||
class Meta:
|
||||
model = UserSpace
|
||||
fields = ('id', 'user', 'space', 'groups', 'active', 'created_at', 'updated_at',)
|
||||
read_only_fields = ('id', 'created_at', 'updated_at', 'space')
|
||||
|
||||
|
||||
class SpacedModelSerializer(serializers.ModelSerializer):
|
||||
def create(self, validated_data):
|
||||
validated_data['space'] = self.context['request'].space
|
||||
return super().create(validated_data)
|
||||
|
||||
|
||||
class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['created_by'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
class Meta:
|
||||
list_serializer_class = SpaceFilterSerializer
|
||||
model = MealType
|
||||
fields = ('id', 'name', 'order', 'icon', 'color', 'default', 'created_by')
|
||||
read_only_fields = ('created_by',)
|
||||
|
||||
|
||||
class UserPreferenceSerializer(WritableNestedModelSerializer):
|
||||
food_inherit_default = serializers.SerializerMethodField('get_food_inherit_defaults')
|
||||
plan_share = UserSerializer(many=True, allow_null=True, required=False)
|
||||
shopping_share = UserSerializer(many=True, allow_null=True, required=False)
|
||||
food_children_exist = serializers.SerializerMethodField('get_food_children_exist')
|
||||
image = UserFileViewSerializer(required=False, allow_null=True, many=False)
|
||||
|
||||
def get_food_inherit_defaults(self, obj):
|
||||
return FoodInheritFieldSerializer(obj.user.get_active_space().food_inherit.all(), many=True).data
|
||||
|
||||
def get_food_children_exist(self, obj):
|
||||
space = getattr(self.context.get('request', None), 'space', None)
|
||||
return Food.objects.filter(depth__gt=0, space=space).exists()
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
with scopes_disabled():
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def create(self, validated_data):
|
||||
raise ValidationError('Cannot create using this endpoint')
|
||||
|
||||
class Meta:
|
||||
model = UserPreference
|
||||
fields = (
|
||||
'user', 'image', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj',
|
||||
'plan_share', 'sticky_navbar',
|
||||
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping',
|
||||
'food_inherit_default', 'default_delay',
|
||||
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days',
|
||||
'csv_delim', 'csv_prefix',
|
||||
'filter_to_supermarket', 'shopping_add_onhand', 'left_handed', 'food_children_exist'
|
||||
)
|
||||
|
||||
|
||||
class StorageSerializer(SpacedModelSerializer):
|
||||
|
||||
def create(self, validated_data):
|
||||
@ -731,6 +740,7 @@ class RecipeSerializer(RecipeBaseSerializer):
|
||||
keywords = KeywordSerializer(many=True)
|
||||
rating = serializers.SerializerMethodField('get_recipe_rating')
|
||||
last_cooked = serializers.SerializerMethodField('get_recipe_last_cooked')
|
||||
shared = UserSerializer(many=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
@ -738,6 +748,7 @@ class RecipeSerializer(RecipeBaseSerializer):
|
||||
'id', 'name', 'description', 'image', 'keywords', 'steps', 'working_time',
|
||||
'waiting_time', 'created_by', 'created_at', 'updated_at', 'source_url',
|
||||
'internal', 'show_ingredient_overview', 'nutrition', 'servings', 'file_path', 'servings_text', 'rating', 'last_cooked',
|
||||
'private', 'shared',
|
||||
)
|
||||
read_only_fields = ['image', 'created_by', 'created_at']
|
||||
|
||||
@ -775,7 +786,7 @@ class CommentSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
class CustomFilterSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
shared = UserNameSerializer(many=True, required=False)
|
||||
shared = UserSerializer(many=True, required=False)
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['created_by'] = self.context['request'].user
|
||||
@ -788,7 +799,7 @@ class CustomFilterSerializer(SpacedModelSerializer, WritableNestedModelSerialize
|
||||
|
||||
|
||||
class RecipeBookSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
shared = UserNameSerializer(many=True)
|
||||
shared = UserSerializer(many=True)
|
||||
filter = CustomFilterSerializer(allow_null=True, required=False)
|
||||
|
||||
def create(self, validated_data):
|
||||
@ -832,7 +843,7 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
meal_type_name = serializers.ReadOnlyField(source='meal_type.name') # TODO deprecate once old meal plan was removed
|
||||
note_markdown = serializers.SerializerMethodField('get_note_markdown')
|
||||
servings = CustomDecimalField()
|
||||
shared = UserNameSerializer(many=True, required=False, allow_null=True)
|
||||
shared = UserSerializer(many=True, required=False, allow_null=True)
|
||||
shopping = serializers.SerializerMethodField('in_shopping')
|
||||
|
||||
def get_note_markdown(self, obj):
|
||||
@ -896,7 +907,7 @@ class ShoppingListEntrySerializer(WritableNestedModelSerializer):
|
||||
ingredient_note = serializers.ReadOnlyField(source='ingredient.note')
|
||||
recipe_mealplan = ShoppingListRecipeSerializer(source='list_recipe', read_only=True)
|
||||
amount = CustomDecimalField()
|
||||
created_by = UserNameSerializer(read_only=True)
|
||||
created_by = UserSerializer(read_only=True)
|
||||
completed_at = serializers.DateTimeField(allow_null=True, required=False)
|
||||
|
||||
def get_fields(self, *args, **kwargs):
|
||||
@ -964,7 +975,7 @@ class ShoppingListEntryCheckedSerializer(serializers.ModelSerializer):
|
||||
class ShoppingListSerializer(WritableNestedModelSerializer):
|
||||
recipes = ShoppingListRecipeSerializer(many=True, allow_null=True)
|
||||
entries = ShoppingListEntrySerializer(many=True, allow_null=True)
|
||||
shared = UserNameSerializer(many=True)
|
||||
shared = UserSerializer(many=True)
|
||||
supermarket = SupermarketSerializer(allow_null=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
@ -1077,7 +1088,7 @@ class InviteLinkSerializer(WritableNestedModelSerializer):
|
||||
if obj.email:
|
||||
try:
|
||||
if InviteLink.objects.filter(space=self.context['request'].space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
|
||||
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.context['request'].user.username)
|
||||
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.context['request'].user.get_user_display_name())
|
||||
message += _(' to join their Tandoor Recipes space ') + escape(self.context['request'].space.name) + '.\n\n'
|
||||
message += _('Click the following link to activate your account: ') + self.context['request'].build_absolute_uri(reverse('view_invite', args=[str(obj.uuid)])) + '\n\n'
|
||||
message += _('If the link does not work use the following code to manually join the space: ') + str(obj.uuid) + '\n\n'
|
||||
@ -1099,7 +1110,7 @@ class InviteLinkSerializer(WritableNestedModelSerializer):
|
||||
class Meta:
|
||||
model = InviteLink
|
||||
fields = (
|
||||
'id', 'uuid', 'email', 'group', 'valid_until', 'used_by', 'created_by', 'created_at',)
|
||||
'id', 'uuid', 'email', 'group', 'valid_until', 'used_by', 'reusable', 'created_by', 'created_at',)
|
||||
read_only_fields = ('id', 'uuid', 'created_by', 'created_at',)
|
||||
|
||||
|
||||
@ -1125,6 +1136,27 @@ class BookmarkletImportSerializer(BookmarkletImportListSerializer):
|
||||
read_only_fields = ('created_by', 'space')
|
||||
|
||||
|
||||
# OAuth / Auth Token related Serializers
|
||||
|
||||
class AccessTokenSerializer(serializers.ModelSerializer):
|
||||
token = serializers.SerializerMethodField('get_token')
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['token'] = f'tda_{str(uuid.uuid4()).replace("-","_")}'
|
||||
validated_data['user'] = self.context['request'].user
|
||||
return super().create(validated_data)
|
||||
|
||||
def get_token(self, obj):
|
||||
if (timezone.now() - obj.created).seconds < 15:
|
||||
return obj.token
|
||||
return f'tda_************_******_***********{obj.token[len(obj.token)-4:]}'
|
||||
|
||||
class Meta:
|
||||
model = AccessToken
|
||||
fields = ('id', 'token', 'expires', 'scope', 'created', 'updated')
|
||||
read_only_fields = ('id', 'token',)
|
||||
|
||||
|
||||
# Export/Import Serializers
|
||||
|
||||
class KeywordExportSerializer(KeywordSerializer):
|
||||
@ -1232,6 +1264,6 @@ class FoodShoppingUpdateSerializer(serializers.ModelSerializer):
|
||||
# non model serializers
|
||||
|
||||
class RecipeFromSourceSerializer(serializers.Serializer):
|
||||
url = serializers.CharField(max_length=4096, required=False, allow_null=True)
|
||||
url = serializers.CharField(max_length=4096, required=False, allow_null=True, allow_blank=True)
|
||||
data = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
||||
bookmarklet = serializers.IntegerField(required=False, allow_null=True, )
|
||||
|
File diff suppressed because one or more lines are too long
1
cookbook/static/css/vue-multiselect.min.css
vendored
1
cookbook/static/css/vue-multiselect.min.css
vendored
File diff suppressed because one or more lines are too long
2
cookbook/static/js/Sortable.min.js
vendored
2
cookbook/static/js/Sortable.min.js
vendored
File diff suppressed because one or more lines are too long
@ -28,7 +28,7 @@
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.setRequestHeader('Authorization', 'Token ' + token);
|
||||
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
|
||||
|
||||
// listen for `onload` event
|
||||
xhr.onload = () => {
|
@ -1,43 +0,0 @@
|
||||
/* frac.js (C) 2012-present SheetJS -- http://sheetjs.com */
|
||||
/*https://developer.aliyun.com/mirror/npm/package/frac/v/0.3.0 Apache license*/
|
||||
var frac = function frac(x, D, mixed) {
|
||||
var n1 = Math.floor(x), d1 = 1;
|
||||
var n2 = n1+1, d2 = 1;
|
||||
if(x !== n1) while(d1 <= D && d2 <= D) {
|
||||
var m = (n1 + n2) / (d1 + d2);
|
||||
if(x === m) {
|
||||
if(d1 + d2 <= D) { d1+=d2; n1+=n2; d2=D+1; }
|
||||
else if(d1 > d2) d2=D+1;
|
||||
else d1=D+1;
|
||||
break;
|
||||
}
|
||||
else if(x < m) { n2 = n1+n2; d2 = d1+d2; }
|
||||
else { n1 = n1+n2; d1 = d1+d2; }
|
||||
}
|
||||
if(d1 > D) { d1 = d2; n1 = n2; }
|
||||
if(!mixed) return [0, n1, d1];
|
||||
var q = Math.floor(n1/d1);
|
||||
return [q, n1 - q*d1, d1];
|
||||
};
|
||||
frac.cont = function cont(x, D, mixed) {
|
||||
var sgn = x < 0 ? -1 : 1;
|
||||
var B = x * sgn;
|
||||
var P_2 = 0, P_1 = 1, P = 0;
|
||||
var Q_2 = 1, Q_1 = 0, Q = 0;
|
||||
var A = Math.floor(B);
|
||||
while(Q_1 < D) {
|
||||
A = Math.floor(B);
|
||||
P = A * P_1 + P_2;
|
||||
Q = A * Q_1 + Q_2;
|
||||
if((B - A) < 0.00000005) break;
|
||||
B = 1 / (B - A);
|
||||
P_2 = P_1; P_1 = P;
|
||||
Q_2 = Q_1; Q_1 = Q;
|
||||
}
|
||||
if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
|
||||
if(!mixed) return [0, sgn * P, Q];
|
||||
var q = Math.floor(sgn * P/Q);
|
||||
return [q, sgn*P - q*Q, Q];
|
||||
};
|
||||
// eslint-disable-next-line no-undef
|
||||
if(typeof module !== 'undefined' && typeof DO_NOT_EXPORT_FRAC === 'undefined') module.exports = frac;
|
6
cookbook/static/js/vue.min.js
vendored
6
cookbook/static/js/vue.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
cookbook/static/themes/tandoor.min.css
vendored
6
cookbook/static/themes/tandoor.min.css
vendored
@ -6113,9 +6113,11 @@ a.close.disabled {
|
||||
.align-text-top {
|
||||
vertical-align: text-top !important
|
||||
}
|
||||
|
||||
/*!
|
||||
* technically the wrong color but not used anywhere besides nav and this way changing nav color is supported
|
||||
*/
|
||||
.bg-primary {
|
||||
background-color: #b98766 !important
|
||||
background-color: rgb(221, 191, 134) !important;
|
||||
}
|
||||
|
||||
a.bg-primary:focus, a.bg-primary:hover, button.bg-primary:focus, button.bg-primary:hover {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import django_tables2 as tables
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext as _
|
||||
@ -8,60 +7,6 @@ from .models import (CookLog, InviteLink, Recipe, RecipeImport,
|
||||
Storage, Sync, SyncLog, ViewLog)
|
||||
|
||||
|
||||
class ImageUrlColumn(tables.Column):
|
||||
def render(self, value):
|
||||
if value.url:
|
||||
return value.url
|
||||
return None
|
||||
|
||||
|
||||
class RecipeTableSmall(tables.Table):
|
||||
id = tables.LinkColumn('edit_recipe', args=[A('id')])
|
||||
name = tables.LinkColumn('view_recipe', args=[A('id')])
|
||||
all_tags = tables.Column(
|
||||
attrs={
|
||||
'td': {'class': 'd-none d-lg-table-cell'},
|
||||
'th': {'class': 'd-none d-lg-table-cell'}
|
||||
}
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
template_name = 'generic/table_template.html'
|
||||
fields = ('id', 'name', 'all_tags')
|
||||
|
||||
|
||||
class RecipeTable(tables.Table):
|
||||
edit = tables.TemplateColumn(
|
||||
"<a style='color: inherit' href='{% url 'edit_recipe' record.id %}' >" + _('Edit') + "</a>" # noqa: E501
|
||||
)
|
||||
name = tables.LinkColumn('view_recipe', args=[A('id')])
|
||||
all_tags = tables.Column(
|
||||
attrs={
|
||||
'td': {'class': 'd-none d-lg-table-cell'},
|
||||
'th': {'class': 'd-none d-lg-table-cell'}
|
||||
}
|
||||
)
|
||||
image = ImageUrlColumn()
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
template_name = 'recipes_table.html'
|
||||
fields = (
|
||||
'id', 'name', 'all_tags', 'description', 'image', 'instructions',
|
||||
'working_time', 'waiting_time', 'internal'
|
||||
)
|
||||
|
||||
|
||||
# class IngredientTable(tables.Table):
|
||||
# id = tables.LinkColumn('edit_food', args=[A('id')])
|
||||
|
||||
# class Meta:
|
||||
# model = Keyword
|
||||
# template_name = 'generic/table_template.html'
|
||||
# fields = ('id', 'name')
|
||||
|
||||
|
||||
class StorageTable(tables.Table):
|
||||
id = tables.LinkColumn('edit_storage', args=[A('id')])
|
||||
|
||||
@ -122,7 +67,6 @@ class RecipeImportTable(tables.Table):
|
||||
fields = ('id', 'name', 'file_path')
|
||||
|
||||
|
||||
|
||||
class InviteLinkTable(tables.Table):
|
||||
link = tables.TemplateColumn(
|
||||
"<input value='{{ request.scheme }}://{{ request.get_host }}{% url 'view_invite' record.uuid %}' class='form-control' />"
|
||||
|
@ -69,7 +69,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-{% nav_color request %} bg-header"
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-{% nav_color request %}"
|
||||
id="id_main_nav"
|
||||
style="{% sticky_nav request %}">
|
||||
|
||||
@ -285,7 +285,7 @@
|
||||
<li class="nav-item dropdown {% if request.resolver_match.url_name in 'view_space,view_settings,view_history,view_system,docs_markdown' %}active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false"><i
|
||||
class="fas fa-fw fa-user-alt"></i> {{ user.get_user_name }}
|
||||
class="fas fa-fw fa-user-alt"></i> {{ user.get_user_display_name }}
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
|
||||
@ -408,6 +408,7 @@
|
||||
localStorage.setItem('BASE_PATH', "{% base_path request 'base' %}")
|
||||
localStorage.setItem('STATIC_URL', "{% base_path request 'static_base' %}")
|
||||
localStorage.setItem('DEBUG', "{% is_debug %}")
|
||||
localStorage.setItem('USER_ID', "{{request.user.pk}}")
|
||||
window.addEventListener("load", () => {
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("{% url 'service_worker' %}", {scope: "{% base_path request 'base' %}" + '/'}).then(function (reg) {
|
||||
|
@ -1,43 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load django_tables2 %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Cookbook" %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{{ units_form.media }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h2><i class="fas fa-shopping-cart"></i> {% trans 'Edit Ingredients' %}</h2>
|
||||
{% blocktrans %}
|
||||
The following form can be used if, accidentally, two (or more) units or ingredients where created that should be
|
||||
the same.
|
||||
It merges two units or ingredients and updates all recipes using them.
|
||||
{% endblocktrans %}
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<h4>{% trans 'Units' %}</h4>
|
||||
<form action="{% url 'edit_food' %}" method="post"
|
||||
onsubmit="return confirm('{% trans 'Are you sure that you want to merge these two units?' %}')">
|
||||
{% csrf_token %}
|
||||
{{ units_form|crispy }}
|
||||
<button class="btn btn-danger" type="submit"
|
||||
><i
|
||||
class="fas fa-sync-alt"></i> {% trans 'Merge' %}</button>
|
||||
</form>
|
||||
|
||||
<h4>{% trans 'Ingredients' %}</h4>
|
||||
<form action="{% url 'edit_food' %}" method="post"
|
||||
onsubmit="return confirm('{% trans 'Are you sure that you want to merge these two ingredients?' %}')">
|
||||
{% csrf_token %}
|
||||
{{ food_form|crispy }}
|
||||
<button class="btn btn-danger" type="submit">
|
||||
<i class="fas fa-sync-alt"></i> {% trans 'Merge' %}</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -1,26 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{% trans 'Import Recipes' %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{{ form.media }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans 'Import' %}</h2>
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<form action="." method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-file-import"></i> {% trans 'Import' %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -1,58 +0,0 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_recipe">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans 'Recipe' %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center">
|
||||
<i class="fas fa-spinner fa-spin fa-8x" id="id_spinner"></i>
|
||||
<a href="" id="a_recipe_open" target="_blank" onclick="afterClick()" style="font-size: 250%"></a>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans 'Close' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="application/javascript">
|
||||
function openRecipe(id) {
|
||||
var link = $('#a_recipe_open');
|
||||
link.hide();
|
||||
$('#id_spinner').show();
|
||||
|
||||
var url = "{% url 'api_get_external_file_link' recipe_id=12345 %}".replace(/12345/, id);
|
||||
|
||||
link.text("{% trans 'Open Recipe' %}");
|
||||
$('#modal_recipe').modal('show');
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4 && this.status === 200) {
|
||||
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
|
||||
link.attr("href", this.responseText);
|
||||
link.show();
|
||||
} else {
|
||||
window.open(this.responseText);
|
||||
$('#modal_recipe').modal('hide');
|
||||
}
|
||||
|
||||
$('#id_spinner').hide();
|
||||
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function afterClick() {
|
||||
$('#modal_recipe').modal('hide');
|
||||
return true;
|
||||
}
|
||||
</script>
|
@ -1,18 +0,0 @@
|
||||
<!--
|
||||
As there is apparently no good way to pass django named URLs to Vue/Webpack we will pack the urls we need into
|
||||
this object and load it in all the templates where we load Vue apps
|
||||
|
||||
Reason for not using other alternatives
|
||||
|
||||
## django-js-reverse
|
||||
bad performance because the 25kb or so path file needs to be loaded before any other request can be made
|
||||
or all paths need to be printed in template which is apparently not recommended for CSP reasons (although this here
|
||||
might do the same)
|
||||
|
||||
-->
|
||||
|
||||
<script type="application/javascript">
|
||||
window.DJANGO_URLS = {
|
||||
'edit_storage'
|
||||
}
|
||||
</script>
|
@ -37,12 +37,6 @@
|
||||
"short_name": "Shopping",
|
||||
"description": "View your shopping lists",
|
||||
"url": "./list/shopping-list/"
|
||||
},
|
||||
{
|
||||
"name": "Latest Shopping List",
|
||||
"short_name": "Shopping List",
|
||||
"description": "View the latest shopping list",
|
||||
"url": "./shopping/latest/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load custom_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans 'Meal Plan View' %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<link rel="stylesheet" href="{% static 'custom/css/markdown_blockquote.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-12">
|
||||
<h3>{{ plan.meal_type }} {{ plan.date }} <a href="{% url 'edit_meal_plan' plan.pk %}"
|
||||
class="d-print-none"><i class="fas fa-pencil-alt"></i></a>
|
||||
</h3>
|
||||
<small class="text-muted">{% trans 'Created by' %} {{ plan.created_by.get_user_name }}</small>
|
||||
{% if plan.shared.all %}
|
||||
<br/><small class="text-muted">{% trans 'Shared with' %}
|
||||
{% for x in plan.shared.all %}{{ x.get_user_name }}{% if not forloop.last %}, {% endif %} {% endfor %}</small>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
{% if plan.title %}
|
||||
<div class="row">
|
||||
<div class="col col-12">
|
||||
<h4>{{ plan.title }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if plan.recipe %}
|
||||
<div class="row">
|
||||
<div class="col col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{% recipe_rating plan.recipe request.user as rating %}
|
||||
<h5 class="card-title"><a
|
||||
href="{% url 'view_recipe' plan.recipe.pk %}">{{ plan.recipe }}</a> {{ rating|safe }}
|
||||
</h5>
|
||||
{% recipe_last plan.recipe request.user as last_cooked %}
|
||||
{% if last_cooked %}
|
||||
{% trans 'Last cooked' %} {{ last_cooked|date }}
|
||||
{% else %}
|
||||
{% trans 'Never cooked before.' %}
|
||||
{% endif %}
|
||||
{% if plan.recipe.keywords %}
|
||||
<br/>
|
||||
<br/>
|
||||
{% for x in plan.recipe.keywords.all %}
|
||||
<span class="badge badge-pill badge-light">{{ x }}</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if plan.note %}
|
||||
<br/>
|
||||
<div class="row">
|
||||
<div class="col col-12">
|
||||
{{ plan.note | markdown | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if same_day_plan %}
|
||||
<br/>
|
||||
<h4>{% trans 'Other meals on this day' %}</h4>
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for x in same_day_plan %}
|
||||
<li class="list-group-item"><a href="{% url 'view_plan_entry' x.pk %}">{{ x.get_label }}
|
||||
({{ x.meal_type }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
32
cookbook/templates/profile.html
Normal file
32
cookbook/templates/profile.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% extends "base.html" %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
|
||||
{% block title %}{% trans 'Profile' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="app" >
|
||||
<profile-view></profile-view>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block script %}
|
||||
{% if debug %}
|
||||
<script src="{% url 'js_reverse' %}"></script>
|
||||
{% else %}
|
||||
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}'
|
||||
</script>
|
||||
|
||||
{% render_bundle 'profile_view' %}
|
||||
{% endblock %}
|
@ -64,7 +64,6 @@
|
||||
|
||||
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}'
|
||||
window.RECIPE_ID = {{recipe.pk}};
|
||||
window.USER_SERVINGS = {{ user_servings }};
|
||||
window.SHARE_UID = '{{ share }}';
|
||||
window.USER_PREF = {
|
||||
'use_fractions': {% if request.user.userpreference.use_fractions %} true {% else %} false {% endif %},
|
||||
|
@ -1,153 +0,0 @@
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
{% load django_tables2 %}
|
||||
{% load static %}
|
||||
{% load custom_tags %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="table-container">
|
||||
{% block table %}
|
||||
<table {% render_attrs table.attrs class="table" %}>
|
||||
{% for row in table.paginated_rows %}
|
||||
<div class="card" style="margin-top: 1px;">
|
||||
<div class="row no-gutters">
|
||||
<div class="col-md-4">
|
||||
<a href="{% url 'view_recipe' row.cells.id %}">
|
||||
{% if row.cells.image|length > 1 %}
|
||||
<img src=" {{ row.cells.image }}" alt="{% trans 'Recipe Image' %}"
|
||||
class="card-img" style="object-fit:cover;height: 160px">
|
||||
{% else %}
|
||||
<img src="{% static 'assets/recipe_no_image.svg' %}"
|
||||
alt="{% trans 'Recipe Image' %}"
|
||||
class="card-img d-none d-md-block"
|
||||
style="object-fit: cover; height: 130px">
|
||||
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card-body" style="padding: 16px">
|
||||
<div class="d-flex">
|
||||
<div class="flex-fill">
|
||||
<h5 class="card-title p-0 m-0">{{ row.cells.name }}
|
||||
{% recipe_rating row.record request.user as rating %}
|
||||
{{ rating|safe }}
|
||||
</h5>
|
||||
{%if row.record.description|length > 0 %}
|
||||
<p class="card-subtitle p-0 m-0 text-muted" style="height:3em; overflow:hidden;">
|
||||
{{ row.cells.description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="card-text{% if not row.record.keywords %} d-none d-lg-block{% endif %}">
|
||||
{% for x in row.record.keywords.all %}
|
||||
<span class="badge badge-pill badge-light">{{ x }}</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
<p class="card-text">
|
||||
{% if row.cells.working_time != 0 %}
|
||||
<span class="badge badge-secondary"><i
|
||||
class="fas fa-user-clock"></i> {% trans 'Preparation time ca.' %} {{ row.cells.working_time }} min </span>
|
||||
{% endif %}
|
||||
|
||||
{% if row.cells.waiting_time != 0 %}
|
||||
<span
|
||||
class="badge badge-secondary"><i
|
||||
class="far fa-clock"></i> {% trans 'Waiting time ca.' %} {{ row.cells.waiting_time }} min </span>
|
||||
{% endif %}
|
||||
{% if not row.record.internal %}
|
||||
<span class="badge badge-info">{% trans 'External' %} </span>
|
||||
{% endif %}
|
||||
{% recipe_last row.record request.user as last_cooked %}
|
||||
{% if last_cooked %}
|
||||
<span class="badge badge-primary">{% trans 'Last cooked' %} {{ last_cooked|date }}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="dropdown">
|
||||
<a class="btn shadow-none" href="#" role="button"
|
||||
id="dropdownMenuLink"
|
||||
data-toggle="dropdown" aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<i class="fas fa-ellipsis-v text-muted"></i>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-right"
|
||||
aria-labelledby="dropdownMenuLink">
|
||||
|
||||
<a class="dropdown-item"
|
||||
href="{% url 'edit_recipe' row.record.pk %}"><i
|
||||
class="fas fa-pencil-alt fa-fw"></i> {% trans 'Edit' %}
|
||||
</a>
|
||||
<button class="dropdown-item"
|
||||
onclick="openCookLogModal({{ row.record.pk }})"><i
|
||||
class="fas fa-clipboard-list fa-fw"></i> {% trans 'Log Cooking' %}
|
||||
</button>
|
||||
<a class="dropdown-item"
|
||||
href="{% url 'delete_recipe' row.record.pk %}"><i
|
||||
class="fas fa-trash fa-fw"></i> {% trans 'Delete' %}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
{% endblock table %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block pagination %}
|
||||
{% if table.page and table.paginator.num_pages > 1 %}
|
||||
<nav aria-label="Table navigation">
|
||||
<ul class="pagination justify-content-center flex-wrap">
|
||||
{% if table.page.has_previous %}
|
||||
{% block pagination.previous %}
|
||||
<li class="previous page-item">
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}"
|
||||
class="page-link">
|
||||
<span aria-hidden="true">«</span>
|
||||
{% trans 'previous' %}
|
||||
</a>
|
||||
</li>
|
||||
{% endblock pagination.previous %}
|
||||
{% endif %}
|
||||
{% if table.page.has_previous or table.page.has_next %}
|
||||
{% block pagination.range %}
|
||||
{% for p in table.page|table_page_range:table.paginator %}
|
||||
<li class="page-item{% if table.page.number == p %} active{% endif %}">
|
||||
<a class="page-link"
|
||||
{% if p != '...' %}href="{% querystring table.prefixed_page_field=p %}"{% endif %}>
|
||||
{{ p }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endblock pagination.range %}
|
||||
{% endif %}
|
||||
{% if table.page.has_next %}
|
||||
{% block pagination.next %}
|
||||
<li class="next page-item">
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}"
|
||||
class="page-link">
|
||||
{% trans 'next' %}
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endblock pagination.next %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock pagination %}
|
||||
{% endblock content %}
|
@ -6,7 +6,7 @@
|
||||
{% block title %}{% trans 'Settings' %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{{ preference_form.media }}
|
||||
{{ search_form.media }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@ -15,209 +15,53 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{% url 'view_settings' %}">{% trans 'Settings' %}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{% trans 'Search' %}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs" id="myTab" role="tablist" style="margin-bottom: 2vh">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if active_tab == 'account' %} active {% endif %}" id="account-tab" data-toggle="tab"
|
||||
href="#account" role="tab"
|
||||
aria-controls="account"
|
||||
aria-selected="{% if active_tab == 'account' %} 'true' {% else %} 'false' {% endif %}">
|
||||
{% trans 'Account' %}</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if active_tab == 'preferences' %} active {% endif %}" id="preferences-tab"
|
||||
data-toggle="tab" href="#preferences" role="tab"
|
||||
aria-controls="preferences"
|
||||
aria-selected="{% if active_tab == 'preferences' %} 'true' {% else %} 'false' {% endif %}">
|
||||
{% trans 'Preferences' %}</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if active_tab == 'api' %} active {% endif %}" id="api-tab" data-toggle="tab"
|
||||
href="#api" role="tab"
|
||||
aria-controls="api"
|
||||
aria-selected="{% if active_tab == 'api' %} 'true' {% else %} 'false' {% endif %}">
|
||||
{% trans 'API-Settings' %}</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if active_tab == 'search' %} active {% endif %}" id="search-tab" data-toggle="tab"
|
||||
href="#search" role="tab"
|
||||
aria-controls="search"
|
||||
aria-selected="{% if active_tab == 'search' %} 'true' {% else %} 'false' {% endif %}">
|
||||
{% trans 'Search-Settings' %}</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if active_tab == 'shopping' %} active {% endif %}" id="shopping-tab" data-toggle="tab"
|
||||
href="#shopping" role="tab"
|
||||
aria-controls="search"
|
||||
aria-selected="{% if active_tab == 'shopping' %} 'true' {% else %} 'false' {% endif %}">
|
||||
{% trans 'Shopping-Settings' %}</a>
|
||||
</li>
|
||||
<div class="tab-pane {% if active_tab == 'search' %} active {% endif %}" id="search" role="tabpanel"
|
||||
aria-labelledby="search-tab">
|
||||
<h4>{% trans 'Search Settings' %}</h4>
|
||||
{% trans 'There are many options to configure the search depending on your personal preferences.' %}
|
||||
{% trans 'Usually you do <b>not need</b> to configure any of them and can just stick with either the default or one of the following presets.' %}
|
||||
{% trans 'If you do want to configure the search you can read about the different options <a href="/docs/search/">here</a>.' %}
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane {% if active_tab == 'account' %} active {% endif %}" id="account" role="tabpanel"
|
||||
aria-labelledby="account-tab">
|
||||
<h4>{% trans 'Name Settings' %}</h4>
|
||||
<form action="." method="post">
|
||||
{% csrf_token %}
|
||||
{{ user_name_form|crispy }}
|
||||
<button class="btn btn-success" type="submit" name="user_name_form"><i
|
||||
class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
</form>
|
||||
|
||||
<h4>{% trans 'Account Settings' %}</h4>
|
||||
|
||||
<a href="{% url 'account_email' %}" class="btn btn-primary">{% trans 'Emails' %}</a>
|
||||
<a href="{% url 'account_change_password' %}" class="btn btn-primary">{% trans 'Password' %}</a>
|
||||
|
||||
<a href="{% url 'socialaccount_connections' %}" class="btn btn-primary">{% trans 'Social' %}</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="card-deck mt-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Fuzzy' %}</h5>
|
||||
<p class="card-text">{% trans 'Find what you need even if your search or the recipe contains typos. Might return more results than needed to make sure you find what you are looking for.' %}</p>
|
||||
<p class="card-text"><small class="text-muted">{% trans 'This is the default behavior' %}</small>
|
||||
</p>
|
||||
<button class="btn btn-primary card-link"
|
||||
onclick="applyPreset('fuzzy')">{% trans 'Apply' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Precise' %}</h5>
|
||||
<p class="card-text">{% trans 'Allows fine control over search results but might not return results if too many spelling mistakes are made.' %}</p>
|
||||
<p class="card-text"><small class="text-muted">{% trans 'Perfect for large Databases' %}</small></p>
|
||||
<button class="btn btn-primary card-link"
|
||||
onclick="applyPreset('precise')">{% trans 'Apply' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="tab-pane {% if active_tab == 'preferences' %} active {% endif %}" id="preferences" role="tabpanel"
|
||||
aria-labelledby="preferences-tab">
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<h4><i class="fas fa-language fa-fw"></i> {% trans 'Language' %}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
|
||||
<input class="form-control" name="next" type="hidden" value="{{ redirect_to }}">
|
||||
<select name="language" class="form-control">
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
{% get_available_languages as LANGUAGES %}
|
||||
{% get_language_info_list for LANGUAGES as languages %}
|
||||
{% for language in languages %}
|
||||
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %}
|
||||
selected{% endif %}>
|
||||
{{ language.name_local }} ({{ language.code }})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<br/>
|
||||
<button class="btn btn-success" type="submit"><i class="fas fa-save"></i> {% trans 'Save' %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<h4><i class="fas fa-palette fa-fw"></i> {% trans 'Style' %}</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<form action="." method="post">
|
||||
{% csrf_token %}
|
||||
{{ preference_form|crispy }}
|
||||
<button class="btn btn-success" type="submit" name="preference_form"><i
|
||||
class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="tab-pane {% if active_tab == 'api' %} active {% endif %}" id="api" role="tabpanel"
|
||||
aria-labelledby="api-tab">
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<h4><i class="fas fa-terminal fa-fw"></i> {% trans 'API Token' %}</h4>
|
||||
{% trans 'You can use both basic authentication and token based authentication to access the REST API.' %}
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<input class="form-control" value="{{ api_token }}" id="id_token">
|
||||
<div class="input-group-append">
|
||||
<button class="input-group-btn btn btn-primary" onclick="copyToken()"><i
|
||||
class="far fa-copy"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
{% trans 'Use the token as an Authorization header prefixed by the word token as shown in the following examples:' %}
|
||||
<br/>
|
||||
<code>Authorization: Token {{ api_token }}</code> {% trans 'or' %}<br/>
|
||||
<code>curl -X GET http://your.domain.com/api/recipes/ -H 'Authorization:
|
||||
Token {{ api_token }}'</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="tab-pane {% if active_tab == 'search' %} active {% endif %}" id="search" role="tabpanel"
|
||||
aria-labelledby="search-tab">
|
||||
<h4>{% trans 'Search Settings' %}</h4>
|
||||
{% trans 'There are many options to configure the search depending on your personal preferences.' %}
|
||||
{% trans 'Usually you do <b>not need</b> to configure any of them and can just stick with either the default or one of the following presets.' %}
|
||||
{% trans 'If you do want to configure the search you can read about the different options <a href="/docs/search/">here</a>.' %}
|
||||
|
||||
<div class="card-deck mt-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Fuzzy' %}</h5>
|
||||
<p class="card-text">{% trans 'Find what you need even if your search or the recipe contains typos. Might return more results than needed to make sure you find what you are looking for.' %}</p>
|
||||
<p class="card-text"><small class="text-muted">{% trans 'This is the default behavior' %}</small></p>
|
||||
<button class="btn btn-primary card-link" onclick="applyPreset('fuzzy')">{% trans 'Apply' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{% trans 'Precise' %}</h5>
|
||||
<p class="card-text">{% trans 'Allows fine control over search results but might not return results if too many spelling mistakes are made.' %}</p>
|
||||
<p class="card-text"><small class="text-muted">{% trans 'Perfect for large Databases' %}</small></p>
|
||||
<button class="btn btn-primary card-link" onclick="applyPreset('precise')">{% trans 'Apply' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
<form action="./#search" method="post" id="id_search_form">
|
||||
{% csrf_token %}
|
||||
{{ search_form|crispy }}
|
||||
<button class="btn btn-success" type="submit" name="search_form" id="search_form_button"><i
|
||||
class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane {% if active_tab == 'shopping' %} active {% endif %}" id="shopping" role="tabpanel"
|
||||
aria-labelledby="shopping-tab">
|
||||
<h4>{% trans 'Shopping Settings' %}</h4>
|
||||
|
||||
<form action="./#shopping" method="post" id="id_shopping_form">
|
||||
{% csrf_token %}
|
||||
{{ shopping_form|crispy }}
|
||||
<button class="btn btn-success" type="submit" name="shopping_form" id="shopping_form_button"><i
|
||||
class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
<form action="./#search" method="post" id="id_search_form">
|
||||
{% csrf_token %}
|
||||
{{ search_form|crispy }}
|
||||
<button class="btn btn-success" type="submit" name="search_form" id="search_form_button"><i
|
||||
class="fas fa-save"></i> {% trans 'Save' %}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script type="application/javascript">
|
||||
$(function() {
|
||||
$(function () {
|
||||
$('#id_search-trigram_threshold').get(0).type = 'range';
|
||||
});
|
||||
|
||||
@ -225,44 +69,5 @@
|
||||
$('#id_search-preset').val(preset);
|
||||
$('#search_form_button').click();
|
||||
}
|
||||
|
||||
function copyToken() {
|
||||
let token = $('#id_token');
|
||||
token.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
|
||||
// Javascript to enable link to tab
|
||||
var hash = location.hash.replace(/^#/, ''); // ^ means starting, meaning only match the first hash
|
||||
if (hash) {
|
||||
$('.nav-tabs a[href="#' + hash + '"]').tab('show');
|
||||
}
|
||||
|
||||
// Change hash for page-reload
|
||||
$('.nav-tabs a').on('shown.bs.tab', function(e) {
|
||||
window.location.hash = e.target.hash;
|
||||
})
|
||||
|
||||
{% comment %}
|
||||
// listen for events
|
||||
$(document).ready(function() {
|
||||
hideShow()
|
||||
// call hideShow when the user clicks on the mealplan_autoadd checkbox
|
||||
$("#id_shopping-mealplan_autoadd_shopping").click(function(event) {
|
||||
hideShow();
|
||||
});
|
||||
})
|
||||
|
||||
function hideShow() {
|
||||
if(document.getElementById('id_shopping-mealplan_autoadd_shopping').checked == true) {
|
||||
$('#div_id_shopping-mealplan_autoexclude_onhand').show();
|
||||
$('#div_id_shopping-mealplan_autoinclude_related').show();
|
||||
}
|
||||
else {
|
||||
$('#div_id_shopping-mealplan_autoexclude_onhand').hide();
|
||||
$('#div_id_shopping-mealplan_autoinclude_related').hide();
|
||||
}
|
||||
}
|
||||
{% endcomment %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -1,18 +1,25 @@
|
||||
{% extends "base.html" %} {% load render_bundle from webpack_loader %} {% load static %} {% load i18n %} {% block title %} {{ title }} {% endblock %} {% block content_fluid %}
|
||||
{% extends "base.html" %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% block title %} {{ title }} {% endblock %}
|
||||
|
||||
<div id="app">
|
||||
<shopping-list-view></shopping-list-view>
|
||||
</div>
|
||||
{% block content_fluid %}
|
||||
|
||||
<div id="app">
|
||||
<shopping-list-view></shopping-list-view>
|
||||
</div>
|
||||
|
||||
{% endblock %} {% block script %} {% if debug %}
|
||||
<script src="{% url 'js_reverse' %}"></script>
|
||||
<script src="{% url 'js_reverse' %}"></script>
|
||||
{% else %}
|
||||
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
|
||||
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
<script type="application/javascript">
|
||||
window.IMAGE_PLACEHOLDER = "{% static 'assets/recipe_no_image.svg' %}"
|
||||
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}'
|
||||
window.SHOPPING_MIN_AUTOSYNC_INTERVAL = {{ SHOPPING_MIN_AUTOSYNC_INTERVAL }}
|
||||
</script>
|
||||
|
||||
{% render_bundle 'shopping_list_view' %} {% endblock %}
|
||||
|
@ -32,15 +32,23 @@
|
||||
{% for us in request.user.userspace_set.all %}
|
||||
|
||||
<div class="card">
|
||||
{% if us.space.image and us.space.image.is_image %}
|
||||
<img style="height: 15vh; object-fit: cover" src="{{ us.space.image.file.url }}"
|
||||
class="card-img-top" alt="Image">
|
||||
{% else %}
|
||||
|
||||
<img style="height: 15vh; object-fit: cover" src="{% static 'assets/recipe_no_image.svg' %}"
|
||||
class="card-img-top" alt="Image">
|
||||
{% endif %}
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><a
|
||||
href="{% url 'view_switch_space' us.space.id %}">{{ us.space.name }}</a>
|
||||
</h5>
|
||||
{# {% if us.active %}#}
|
||||
{# <i class="far fa-dot-circle fa-fw"></i>#}
|
||||
{# {% else %}#}
|
||||
{# <i class="far fa-circle fa-fw"></i>#}
|
||||
{# {% endif %}#}
|
||||
{# {% if us.active %}#}
|
||||
{# <i class="far fa-dot-circle fa-fw"></i>#}
|
||||
{# {% else %}#}
|
||||
{# <i class="far fa-circle fa-fw"></i>#}
|
||||
{# {% endif %}#}
|
||||
<p class="card-text"><small
|
||||
class="text-muted">{% trans 'Owner' %}: {{ us.space.created_by }}</small>
|
||||
{% if us.space.created_by != us.user %}
|
||||
|
@ -1,53 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans 'Stats' %}{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-12">
|
||||
<h3>{% trans 'Statistics' %} </h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
{% trans 'Number of objects' %}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">{% trans 'Recipes' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.recipes }}</span></li>
|
||||
<li class="list-group-item">{% trans 'Keywords' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.keywords }}</span></li>
|
||||
<li class="list-group-item">{% trans 'Units' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.units }}</span></li>
|
||||
<li class="list-group-item">{% trans 'Ingredients' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.ingredients }}</span></li>
|
||||
<li class="list-group-item">{% trans 'Recipe Imports' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.recipe_import }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
{% trans 'Objects stats' %}
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">{% trans 'Recipes without Keywords' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.recipes_no_keyword }}</span></li>
|
||||
<li class="list-group-item">{% trans 'External Recipes' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.recipes_external }}</span></li>
|
||||
<li class="list-group-item">{% trans 'Internal Recipes' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.recipes_internal }}</span></li>
|
||||
<li class="list-group-item">{% trans 'Comments' %} : <span
|
||||
class="badge badge-pill badge-info">{{ counts.comments }}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -11,19 +11,7 @@
|
||||
{% block content %}
|
||||
|
||||
<h1>{% trans 'System' %}</h1>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h3>{% trans 'Invite Links' %}</h3>
|
||||
<a href="{% url 'list_invite_link' %}" class="btn btn-success">{% trans 'Show Links' %}</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
|
46
cookbook/templates/user_settings.html
Normal file
46
cookbook/templates/user_settings.html
Normal file
@ -0,0 +1,46 @@
|
||||
{% extends "base.html" %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load custom_tags %}
|
||||
|
||||
{% block title %}{% trans 'Settings' %}{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div id="app">
|
||||
|
||||
<settings-view></settings-view>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block script %}
|
||||
{% if debug %}
|
||||
<script src="{% url 'js_reverse' %}"></script>
|
||||
{% else %}
|
||||
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
|
||||
{% endif %}
|
||||
|
||||
<script type="application/javascript">
|
||||
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}'
|
||||
window.USER_ID = {{ request.user.pk }}
|
||||
window.SHOPPING_MIN_AUTOSYNC_INTERVAL = {{ SHOPPING_MIN_AUTOSYNC_INTERVAL }}
|
||||
|
||||
<!--TODO build custom API endpoint for this -->
|
||||
{% get_available_languages as LANGUAGES %}
|
||||
{% get_language_info_list for LANGUAGES as languages %}
|
||||
window.AVAILABLE_LANGUAGES = [
|
||||
{% for language in languages %}
|
||||
['{{ language.name_local }}', '{{ language.code }}'],
|
||||
{% endfor %}
|
||||
]
|
||||
|
||||
</script>
|
||||
|
||||
{% render_bundle 'settings_view' %}
|
||||
{% endblock %}
|
@ -151,7 +151,7 @@ def bookmarklet(request):
|
||||
localStorage.setItem('redirectURL', '" + server + reverse('data_import_url') + "'); \
|
||||
localStorage.setItem('token', '" + api_token.__str__() + "'); \
|
||||
document.body.appendChild(document.createElement(\'script\')).src=\'" \
|
||||
+ server + prefix + static('js/bookmarklet.js') + "? \
|
||||
+ server + prefix + static('js/bookmarklet_v3.js') + "? \
|
||||
r=\'+Math.floor(Math.random()*999999999);}})();'>Test</a>"
|
||||
return re.sub(r"[\n\t]*", "", bookmark)
|
||||
|
||||
|
115
cookbook/tests/api/test_api_access_token.py
Normal file
115
cookbook/tests/api/test_api_access_token.py
Normal file
@ -0,0 +1,115 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django_scopes import scopes_disabled
|
||||
from oauth2_provider.models import AccessToken
|
||||
|
||||
from cookbook.models import ViewLog
|
||||
|
||||
LIST_URL = 'api:accesstoken-list'
|
||||
DETAIL_URL = 'api:accesstoken-detail'
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def obj_1(u1_s1):
|
||||
return AccessToken.objects.create(user=auth.get_user(u1_s1), scope='test', expires=timezone.now() + timezone.timedelta(days=365 * 5), token='test1')
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def obj_2(u1_s1):
|
||||
return AccessToken.objects.create(user=auth.get_user(u1_s1), scope='test', expires=timezone.now() + timezone.timedelta(days=365 * 5), token='test2')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 200],
|
||||
['u1_s1', 200],
|
||||
['a1_s1', 200],
|
||||
])
|
||||
def test_list_permission(arg, request):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
assert c.get(reverse(LIST_URL)).status_code == arg[1]
|
||||
|
||||
|
||||
def test_list_space(obj_1, obj_2, u1_s1, u1_s2, space_2):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 2
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 0
|
||||
|
||||
obj_1.user = auth.get_user(u1_s2)
|
||||
obj_1.save()
|
||||
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 1
|
||||
|
||||
|
||||
def test_token_visibility(u1_s1, obj_1):
|
||||
# tokens should only be returned on the first API request (first 15 seconds)
|
||||
at = json.loads(u1_s1.get(reverse(DETAIL_URL, args=[obj_1.id])).content)
|
||||
assert at['token'] == obj_1.token
|
||||
with scopes_disabled():
|
||||
obj_1.created = timezone.now() - timezone.timedelta(seconds=16)
|
||||
obj_1.save()
|
||||
at = json.loads(u1_s1.get(reverse(DETAIL_URL, args=[obj_1.id])).content)
|
||||
assert at['token'] != obj_1.token
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 404],
|
||||
['u1_s1', 200],
|
||||
['a1_s1', 404],
|
||||
['g1_s2', 404],
|
||||
['u1_s2', 404],
|
||||
['a1_s2', 404],
|
||||
])
|
||||
def test_update(arg, request, obj_1):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
r = c.patch(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={obj_1.id}
|
||||
),
|
||||
{'scope': 'lorem ipsum'},
|
||||
content_type='application/json'
|
||||
)
|
||||
assert r.status_code == arg[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 201],
|
||||
['u1_s1', 201],
|
||||
['a1_s1', 201],
|
||||
])
|
||||
def test_add(arg, request, u1_s2, u2_s1, recipe_1_s1):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
r = c.post(
|
||||
reverse(LIST_URL),
|
||||
{'scope': 'test', 'expires': timezone.now() + timezone.timedelta(days=365 * 5)},
|
||||
content_type='application/json'
|
||||
)
|
||||
response = json.loads(r.content)
|
||||
assert r.status_code == arg[1]
|
||||
if r.status_code == 201:
|
||||
assert response['scope'] == 'test'
|
||||
|
||||
|
||||
def test_delete(u1_s1, u1_s2, obj_1):
|
||||
r = u1_s2.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={obj_1.id}
|
||||
)
|
||||
)
|
||||
assert r.status_code == 404
|
||||
|
||||
r = u1_s1.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={obj_1.id}
|
||||
)
|
||||
)
|
||||
assert r.status_code == 204
|
@ -1,6 +1,7 @@
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from django.contrib import auth
|
||||
from django.urls import reverse
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
@ -30,6 +31,7 @@ def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 1
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
|
||||
# test for space filter
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.space = space_2
|
||||
recipe_1_s1.save()
|
||||
@ -37,8 +39,23 @@ def test_list_space(recipe_1_s1, u1_s1, u1_s2, space_2):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 1
|
||||
|
||||
# test for private recipe filter
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_1_s1.private = True
|
||||
recipe_1_s1.save()
|
||||
|
||||
def test_share_permission(recipe_1_s1, u1_s1, u1_s2, a_u):
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 0
|
||||
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s2)
|
||||
recipe_1_s1.save()
|
||||
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)['results']) == 1
|
||||
|
||||
|
||||
def test_share_permission(recipe_1_s1, u1_s1, u1_s2, u2_s1, a_u):
|
||||
assert u1_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 200
|
||||
assert u1_s2.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 404
|
||||
|
||||
@ -52,6 +69,15 @@ def test_share_permission(recipe_1_s1, u1_s1, u1_s2, a_u):
|
||||
assert u1_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u1_s2.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 404 # TODO fix in https://github.com/TandoorRecipes/recipes/issues/1238
|
||||
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_1_s1.private = True
|
||||
recipe_1_s1.save()
|
||||
|
||||
assert a_u.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u1_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u2_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk]) + f'?share={share.uuid}').status_code == 200
|
||||
assert u2_s1.get(reverse(DETAIL_URL, args=[recipe_1_s1.pk])).status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
@ -80,6 +106,38 @@ def test_update(arg, request, recipe_1_s1):
|
||||
validate_recipe(j, json.loads(r.content))
|
||||
|
||||
|
||||
def test_update_share(u1_s1, u2_s1, u1_s2, recipe_1_s1):
|
||||
with scopes_disabled():
|
||||
r = u1_s1.patch(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={recipe_1_s1.id}
|
||||
),
|
||||
{'shared': [{'id': auth.get_user(u1_s2).pk, 'username': auth.get_user(u1_s2).username}, {'id': auth.get_user(u2_s1).pk, 'username': auth.get_user(u2_s1).username}]},
|
||||
content_type='application/json'
|
||||
)
|
||||
response = json.loads(r.content)
|
||||
assert r.status_code == 200
|
||||
assert len(response['shared']) == 1
|
||||
assert response['shared'][0]['id'] == auth.get_user(u2_s1).pk
|
||||
|
||||
|
||||
def test_update_private_recipe(u1_s1, u2_s1, recipe_1_s1):
|
||||
r = u1_s1.patch(reverse(DETAIL_URL, args={recipe_1_s1.id}), {'name': 'test1'}, content_type='application/json')
|
||||
assert r.status_code == 200
|
||||
|
||||
with scopes_disabled():
|
||||
recipe_1_s1.private = True
|
||||
recipe_1_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_1_s1.save()
|
||||
|
||||
r = u1_s1.patch(reverse(DETAIL_URL, args={recipe_1_s1.id}), {'name': 'test2'}, content_type='application/json')
|
||||
assert r.status_code == 200
|
||||
|
||||
r = u2_s1.patch(reverse(DETAIL_URL, args={recipe_1_s1.id}), {'name': 'test3'}, content_type='application/json')
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 201],
|
||||
@ -107,22 +165,22 @@ def test_add(arg, request, u1_s2):
|
||||
x += 1
|
||||
|
||||
|
||||
def test_delete(u1_s1, u1_s2, recipe_1_s1):
|
||||
def test_delete(u1_s1, u1_s2, u2_s1, recipe_1_s1, recipe_2_s1):
|
||||
with scopes_disabled():
|
||||
r = u1_s2.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={recipe_1_s1.id}
|
||||
)
|
||||
)
|
||||
r = u1_s2.delete(reverse(DETAIL_URL, args={recipe_1_s1.id}))
|
||||
assert r.status_code == 404
|
||||
|
||||
r = u1_s1.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={recipe_1_s1.id}
|
||||
)
|
||||
)
|
||||
r = u1_s1.delete(reverse(DETAIL_URL, args={recipe_1_s1.id}))
|
||||
|
||||
assert r.status_code == 204
|
||||
assert not Recipe.objects.filter(pk=recipe_1_s1.id).exists()
|
||||
|
||||
recipe_2_s1.created_by = auth.get_user(u1_s1)
|
||||
recipe_2_s1.private = True
|
||||
recipe_2_s1.save()
|
||||
|
||||
r = u2_s1.delete(reverse(DETAIL_URL, args={recipe_2_s1.id}))
|
||||
assert r.status_code == 403
|
||||
|
||||
r = u1_s1.delete(reverse(DETAIL_URL, args={recipe_2_s1.id}))
|
||||
assert r.status_code == 204
|
||||
|
@ -7,22 +7,11 @@ from django.urls import reverse
|
||||
|
||||
from cookbook.models import UserSpace
|
||||
|
||||
LIST_URL = 'api:username-list'
|
||||
DETAIL_URL = 'api:username-detail'
|
||||
LIST_URL = 'api:user-list'
|
||||
DETAIL_URL = 'api:user-detail'
|
||||
|
||||
|
||||
def test_forbidden_methods(u1_s1):
|
||||
r = u1_s1.post(
|
||||
reverse(LIST_URL))
|
||||
assert r.status_code == 405
|
||||
|
||||
r = u1_s1.put(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args=[auth.get_user(u1_s1).pk])
|
||||
)
|
||||
assert r.status_code == 405
|
||||
|
||||
r = u1_s1.delete(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
@ -69,3 +58,56 @@ def test_list_space(u1_s1, u2_s1, u1_s2, space_2):
|
||||
|
||||
assert len(json.loads(u1_s1.get(reverse(LIST_URL)).content)) == 1
|
||||
assert len(json.loads(u1_s2.get(reverse(LIST_URL)).content)) == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 403],
|
||||
['g1_s1', 403],
|
||||
['u1_s1', 200],
|
||||
['a1_s1', 403],
|
||||
['g1_s2', 404],
|
||||
['u1_s2', 404],
|
||||
['a1_s2', 404],
|
||||
])
|
||||
def test_user_retrieve(arg, request, u1_s1):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
|
||||
r = c.get(reverse(DETAIL_URL, args={auth.get_user(u1_s1).id}), )
|
||||
print(r.content, auth.get_user(u1_s1).username)
|
||||
assert r.status_code == arg[1]
|
||||
|
||||
|
||||
def test_user_update(u1_s1, u2_s1,u1_s2):
|
||||
# can update own user
|
||||
r = u1_s1.patch(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={auth.get_user(u1_s1).id}
|
||||
),
|
||||
{'first_name': 'test'},
|
||||
content_type='application/json'
|
||||
)
|
||||
response = json.loads(r.content)
|
||||
assert r.status_code == 200
|
||||
assert response['first_name'] == 'test'
|
||||
|
||||
# can't update another user
|
||||
r = u1_s1.patch(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={auth.get_user(u2_s1).id}
|
||||
),
|
||||
{'first_name': 'test'},
|
||||
content_type='application/json'
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
r = u1_s1.patch(
|
||||
reverse(
|
||||
DETAIL_URL,
|
||||
args={auth.get_user(u1_s2).id}
|
||||
),
|
||||
{'first_name': 'test'},
|
||||
content_type='application/json'
|
||||
)
|
||||
assert r.status_code == 404
|
@ -47,10 +47,11 @@ router.register(r'sync', api.SyncViewSet)
|
||||
router.register(r'sync-log', api.SyncLogViewSet)
|
||||
router.register(r'unit', api.UnitViewSet)
|
||||
router.register(r'user-file', api.UserFileViewSet)
|
||||
router.register(r'user-name', api.UserNameViewSet, basename='username')
|
||||
router.register(r'user', api.UserViewSet)
|
||||
router.register(r'user-preference', api.UserPreferenceViewSet)
|
||||
router.register(r'user-space', api.UserSpaceViewSet)
|
||||
router.register(r'view-log', api.ViewLogViewSet)
|
||||
router.register(r'access-token', api.AccessTokenViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='index'),
|
||||
@ -59,23 +60,22 @@ urlpatterns = [
|
||||
path('space-overview', views.space_overview, name='view_space_overview'),
|
||||
path('space-manage/<int:space_id>', views.space_manage, name='view_space_manage'),
|
||||
path('switch-space/<int:space_id>', views.switch_space, name='view_switch_space'),
|
||||
path('profile/<int:user_id>', views.view_profile, name='view_profile'),
|
||||
path('no-perm', views.no_perm, name='view_no_perm'),
|
||||
path('invite/<slug:token>', views.invite_link, name='view_invite'),
|
||||
path('system/', views.system, name='view_system'),
|
||||
path('search/', views.search, name='view_search'),
|
||||
path('search/v2/', views.search_v2, name='view_search_v2'),
|
||||
path('books/', views.books, name='view_books'),
|
||||
path('plan/', views.meal_plan, name='view_plan'),
|
||||
path('plan/entry/<int:pk>', views.meal_plan_entry, name='view_plan_entry'),
|
||||
path('shopping/latest/', lists.shopping_list, name='view_shopping_latest'),
|
||||
path('shopping/', lists.shopping_list, name='view_shopping'),
|
||||
path('settings/', views.user_settings, name='view_settings'),
|
||||
path('settings-shopping/', views.shopping_settings, name='view_shopping_settings'),
|
||||
path('history/', views.history, name='view_history'),
|
||||
path('supermarket/', views.supermarket, name='view_supermarket'),
|
||||
path('ingredient-editor/', views.ingredient_editor, name='view_ingredient_editor'),
|
||||
path('abuse/<slug:token>', views.report_share_abuse, name='view_report_share_abuse'),
|
||||
|
||||
path('import/', import_export.import_recipe, name='view_import'),
|
||||
path('api/import/', api.import_files, name='view_import'),
|
||||
path('import-response/<int:pk>/', import_export.import_response, name='view_import_response'),
|
||||
path('export/', import_export.export_recipe, name='view_export'),
|
||||
path('export-response/<int:pk>/', import_export.export_response, name='view_export_response'),
|
||||
@ -103,7 +103,6 @@ urlpatterns = [
|
||||
path('data/batch/edit', data.batch_edit, name='data_batch_edit'),
|
||||
path('data/batch/import', data.batch_import, name='data_batch_import'),
|
||||
path('data/sync/wait', data.sync_wait, name='data_sync_wait'),
|
||||
path('data/statistics', data.statistics, name='data_stats'),
|
||||
path('data/import/url', data.import_url, name='data_import_url'),
|
||||
|
||||
path('api/get_external_file_link/<int:recipe_id>/', api.get_external_file_link, name='api_get_external_file_link'),
|
||||
|
@ -2,9 +2,12 @@ import io
|
||||
import json
|
||||
import mimetypes
|
||||
import re
|
||||
import threading
|
||||
import traceback
|
||||
import uuid
|
||||
from collections import OrderedDict
|
||||
from json import JSONDecodeError
|
||||
from urllib.parse import unquote
|
||||
from zipfile import ZipFile
|
||||
|
||||
import requests
|
||||
@ -13,23 +16,25 @@ from PIL import UnidentifiedImageError
|
||||
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, Group
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.contrib.postgres.search import TrigramSimilarity
|
||||
from django.core.exceptions import FieldError, ValidationError
|
||||
from django.core.files import File
|
||||
from django.db.models import (Case, Count, Exists, OuterRef, ProtectedError, Q,
|
||||
Subquery, Value, When)
|
||||
from django.db.models import Case, Count, Exists, OuterRef, ProtectedError, Q, Subquery, Value, When
|
||||
from django.db.models.fields.related import ForeignObjectRel
|
||||
from django.db.models.functions import Coalesce, Lower
|
||||
from django.http import FileResponse, HttpResponse, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from icalendar import Calendar, Event
|
||||
from oauth2_provider.models import AccessToken
|
||||
from recipe_scrapers import scrape_me
|
||||
from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
|
||||
from requests.exceptions import MissingSchema
|
||||
from rest_framework import decorators, status, viewsets
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.exceptions import APIException, PermissionDenied
|
||||
@ -41,43 +46,49 @@ from rest_framework.throttling import AnonRateThrottle
|
||||
from rest_framework.viewsets import ViewSetMixin
|
||||
from treebeard.exceptions import InvalidMoveToDescendant, InvalidPosition, PathOverflow
|
||||
|
||||
from cookbook.forms import ImportForm
|
||||
from cookbook.helper import recipe_url_import as helper
|
||||
from cookbook.helper.HelperFunctions import str2bool
|
||||
from cookbook.helper.image_processing import handle_image
|
||||
from cookbook.helper.ingredient_parser import IngredientParser
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest, CustomIsOwner,
|
||||
CustomIsShare, CustomIsShared, CustomIsUser,
|
||||
group_required, CustomIsSpaceOwner, switch_user_active_space, is_space_owner, CustomIsOwnerReadOnly)
|
||||
from cookbook.helper.recipe_html_import import get_recipe_from_source
|
||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch, old_search
|
||||
from cookbook.helper.recipe_url_import import get_from_youtube_scraper
|
||||
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsOwner,
|
||||
CustomIsOwnerReadOnly, CustomIsShared,
|
||||
CustomIsSpaceOwner, CustomIsUser, group_required,
|
||||
is_space_owner, switch_user_active_space, above_space_limit, CustomRecipePermission, CustomUserPermission, CustomTokenHasReadWriteScope, CustomTokenHasScope)
|
||||
from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch
|
||||
from cookbook.helper.recipe_url_import import get_from_youtube_scraper, get_images_from_soup
|
||||
from cookbook.helper.scrapers.scrapers import text_scraper
|
||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
|
||||
from cookbook.models import (Automation, BookmarkletImport, CookLog, CustomFilter, ExportLog, Food,
|
||||
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
|
||||
Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
||||
ShoppingListEntry, ShoppingListRecipe, Step, Storage, Supermarket,
|
||||
SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit,
|
||||
UserFile, UserPreference, ViewLog, Space, UserSpace, InviteLink)
|
||||
FoodInheritField, ImportLog, Ingredient, InviteLink, Keyword, MealPlan,
|
||||
MealType, Recipe, RecipeBook, RecipeBookEntry, ShareLink, ShoppingList,
|
||||
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
|
||||
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
|
||||
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog)
|
||||
from cookbook.provider.dropbox import Dropbox
|
||||
from cookbook.provider.local import Local
|
||||
from cookbook.provider.nextcloud import Nextcloud
|
||||
from cookbook.schemas import FilterSchema, QueryParam, QueryParamAutoSchema, TreeSchema
|
||||
from cookbook.serializer import (AutomationSerializer, BookmarkletImportSerializer,
|
||||
CookLogSerializer, CustomFilterSerializer, ExportLogSerializer,
|
||||
from cookbook.serializer import (AutomationSerializer, BookmarkletImportListSerializer,
|
||||
BookmarkletImportSerializer, CookLogSerializer,
|
||||
CustomFilterSerializer, ExportLogSerializer,
|
||||
FoodInheritFieldSerializer, FoodSerializer,
|
||||
FoodShoppingUpdateSerializer, ImportLogSerializer,
|
||||
IngredientSerializer, KeywordSerializer, MealPlanSerializer,
|
||||
FoodShoppingUpdateSerializer, GroupSerializer, ImportLogSerializer,
|
||||
IngredientSerializer, IngredientSimpleSerializer,
|
||||
InviteLinkSerializer, KeywordSerializer, MealPlanSerializer,
|
||||
MealTypeSerializer, RecipeBookEntrySerializer,
|
||||
RecipeBookSerializer, RecipeImageSerializer,
|
||||
RecipeOverviewSerializer, RecipeSerializer,
|
||||
RecipeBookSerializer, RecipeFromSourceSerializer,
|
||||
RecipeImageSerializer, RecipeOverviewSerializer, RecipeSerializer,
|
||||
RecipeShoppingUpdateSerializer, RecipeSimpleSerializer,
|
||||
ShoppingListAutoSyncSerializer, ShoppingListEntrySerializer,
|
||||
ShoppingListRecipeSerializer, ShoppingListSerializer,
|
||||
StepSerializer, StorageSerializer,
|
||||
SpaceSerializer, StepSerializer, StorageSerializer,
|
||||
SupermarketCategoryRelationSerializer,
|
||||
SupermarketCategorySerializer, SupermarketSerializer,
|
||||
SyncLogSerializer, SyncSerializer, UnitSerializer,
|
||||
UserFileSerializer, UserNameSerializer, UserPreferenceSerializer,
|
||||
ViewLogSerializer, IngredientSimpleSerializer, BookmarkletImportListSerializer, RecipeFromSourceSerializer, SpaceSerializer, UserSpaceSerializer, GroupSerializer, InviteLinkSerializer)
|
||||
UserFileSerializer, UserSerializer, UserPreferenceSerializer,
|
||||
UserSpaceSerializer, ViewLogSerializer, AccessTokenSerializer)
|
||||
from cookbook.views.import_export import get_integration
|
||||
from recipes import settings
|
||||
|
||||
|
||||
@ -344,7 +355,7 @@ class TreeMixin(MergeMixin, FuzzyFilterMixin, ExtendedRecipeMixin):
|
||||
return Response(content, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class UserViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
list:
|
||||
optional parameters
|
||||
@ -352,9 +363,9 @@ class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
- **filter_list**: array of user id's to get names for
|
||||
"""
|
||||
queryset = User.objects
|
||||
serializer_class = UserNameSerializer
|
||||
permission_classes = [CustomIsGuest]
|
||||
http_method_names = ['get']
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = [CustomUserPermission & CustomTokenHasReadWriteScope]
|
||||
http_method_names = ['get', 'patch']
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.filter(userspace__space=self.request.space)
|
||||
@ -371,14 +382,14 @@ class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class GroupViewSet(viewsets.ModelViewSet):
|
||||
queryset = Group.objects.all()
|
||||
serializer_class = GroupSerializer
|
||||
permission_classes = [CustomIsAdmin]
|
||||
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
http_method_names = ['get', ]
|
||||
|
||||
|
||||
class SpaceViewSet(viewsets.ModelViewSet):
|
||||
queryset = Space.objects
|
||||
serializer_class = SpaceSerializer
|
||||
permission_classes = [CustomIsOwner & CustomIsAdmin]
|
||||
permission_classes = [CustomIsOwner & CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
http_method_names = ['get', 'patch']
|
||||
|
||||
def get_queryset(self):
|
||||
@ -388,7 +399,7 @@ class SpaceViewSet(viewsets.ModelViewSet):
|
||||
class UserSpaceViewSet(viewsets.ModelViewSet):
|
||||
queryset = UserSpace.objects
|
||||
serializer_class = UserSpaceSerializer
|
||||
permission_classes = [CustomIsSpaceOwner | CustomIsOwnerReadOnly]
|
||||
permission_classes = [(CustomIsSpaceOwner | CustomIsOwnerReadOnly) & CustomTokenHasReadWriteScope]
|
||||
http_method_names = ['get', 'patch', 'delete']
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
@ -406,7 +417,7 @@ class UserSpaceViewSet(viewsets.ModelViewSet):
|
||||
class UserPreferenceViewSet(viewsets.ModelViewSet):
|
||||
queryset = UserPreference.objects
|
||||
serializer_class = UserPreferenceSerializer
|
||||
permission_classes = [CustomIsOwner, ]
|
||||
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
|
||||
http_method_names = ['get', 'patch', ]
|
||||
|
||||
def get_queryset(self):
|
||||
@ -418,7 +429,7 @@ class StorageViewSet(viewsets.ModelViewSet):
|
||||
# TODO handle delete protect error and adjust test
|
||||
queryset = Storage.objects
|
||||
serializer_class = StorageSerializer
|
||||
permission_classes = [CustomIsAdmin, ]
|
||||
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.space)
|
||||
@ -427,7 +438,7 @@ class StorageViewSet(viewsets.ModelViewSet):
|
||||
class SyncViewSet(viewsets.ModelViewSet):
|
||||
queryset = Sync.objects
|
||||
serializer_class = SyncSerializer
|
||||
permission_classes = [CustomIsAdmin, ]
|
||||
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(space=self.request.space)
|
||||
@ -436,7 +447,7 @@ class SyncViewSet(viewsets.ModelViewSet):
|
||||
class SyncLogViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SyncLog.objects
|
||||
serializer_class = SyncLogSerializer
|
||||
permission_classes = [CustomIsAdmin, ]
|
||||
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -446,7 +457,7 @@ class SyncLogViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class SupermarketViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = Supermarket.objects
|
||||
serializer_class = SupermarketSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(space=self.request.space)
|
||||
@ -457,7 +468,7 @@ class SupermarketCategoryViewSet(viewsets.ModelViewSet, FuzzyFilterMixin):
|
||||
queryset = SupermarketCategory.objects
|
||||
model = SupermarketCategory
|
||||
serializer_class = SupermarketCategorySerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(space=self.request.space).order_by(Lower('name').asc())
|
||||
@ -467,7 +478,7 @@ class SupermarketCategoryViewSet(viewsets.ModelViewSet, FuzzyFilterMixin):
|
||||
class SupermarketCategoryRelationViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = SupermarketCategoryRelation.objects
|
||||
serializer_class = SupermarketCategoryRelationSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -479,7 +490,7 @@ class KeywordViewSet(viewsets.ModelViewSet, TreeMixin):
|
||||
queryset = Keyword.objects
|
||||
model = Keyword
|
||||
serializer_class = KeywordSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
|
||||
@ -487,14 +498,14 @@ class UnitViewSet(viewsets.ModelViewSet, MergeMixin, FuzzyFilterMixin):
|
||||
queryset = Unit.objects
|
||||
model = Unit
|
||||
serializer_class = UnitSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
|
||||
class FoodInheritFieldViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = FoodInheritField.objects
|
||||
serializer_class = FoodInheritFieldSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
# exclude fields not yet implemented
|
||||
@ -506,7 +517,7 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
|
||||
queryset = Food.objects
|
||||
model = Food
|
||||
serializer_class = FoodSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -517,9 +528,10 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
|
||||
shopping_status = ShoppingListEntry.objects.filter(space=self.request.space, food=OuterRef('id'),
|
||||
checked=False).values('id')
|
||||
# onhand_status = self.queryset.annotate(onhand_status=Exists(onhand_users_set__in=[shared_users]))
|
||||
return self.queryset.annotate(shopping_status=Exists(shopping_status)).prefetch_related('onhand_users',
|
||||
'inherit_fields').select_related(
|
||||
'recipe', 'supermarket_category')
|
||||
return self.queryset\
|
||||
.annotate(shopping_status=Exists(shopping_status))\
|
||||
.prefetch_related('onhand_users', 'inherit_fields', 'child_inherit_fields', 'substitute')\
|
||||
.select_related('recipe', 'supermarket_category')
|
||||
|
||||
@decorators.action(detail=True, methods=['PUT'], serializer_class=FoodShoppingUpdateSerializer, )
|
||||
# TODO DRF only allows one action in a decorator action without overriding get_operation_id_base() this should be PUT and DELETE probably
|
||||
@ -554,7 +566,7 @@ class FoodViewSet(viewsets.ModelViewSet, TreeMixin):
|
||||
class RecipeBookViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = RecipeBook.objects
|
||||
serializer_class = RecipeBookSerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(Q(created_by=self.request.user) | Q(shared=self.request.user)).filter(
|
||||
@ -573,7 +585,7 @@ class RecipeBookEntryViewSet(viewsets.ModelViewSet, viewsets.GenericViewSet):
|
||||
"""
|
||||
queryset = RecipeBookEntry.objects
|
||||
serializer_class = RecipeBookEntrySerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.filter(
|
||||
@ -601,7 +613,7 @@ class MealPlanViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
queryset = MealPlan.objects
|
||||
serializer_class = MealPlanSerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.filter(
|
||||
@ -626,7 +638,7 @@ class MealTypeViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
queryset = MealType.objects
|
||||
serializer_class = MealTypeSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = self.queryset.order_by('order', 'id').filter(created_by=self.request.user).filter(
|
||||
@ -637,7 +649,7 @@ class MealTypeViewSet(viewsets.ModelViewSet):
|
||||
class IngredientViewSet(viewsets.ModelViewSet):
|
||||
queryset = Ingredient.objects
|
||||
serializer_class = IngredientSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_serializer_class(self):
|
||||
@ -661,7 +673,7 @@ class IngredientViewSet(viewsets.ModelViewSet):
|
||||
class StepViewSet(viewsets.ModelViewSet):
|
||||
queryset = Step.objects
|
||||
serializer_class = StepSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
query_params = [
|
||||
QueryParam(name='recipe', description=_('ID of recipe a step is part of. For multiple repeat parameter.'),
|
||||
@ -705,7 +717,7 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
queryset = Recipe.objects
|
||||
serializer_class = RecipeSerializer
|
||||
# TODO split read and write permission for meal plan guest
|
||||
permission_classes = [CustomIsShare | CustomIsGuest]
|
||||
permission_classes = [CustomRecipePermission & CustomTokenHasReadWriteScope]
|
||||
pagination_class = RecipePagination
|
||||
|
||||
query_params = [
|
||||
@ -772,13 +784,14 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
def get_queryset(self):
|
||||
share = self.request.query_params.get('share', None)
|
||||
|
||||
if self.detail:
|
||||
if not share:
|
||||
if self.detail: # if detail request and not list, private condition is verified by permission class
|
||||
if not share: # filter for space only if not shared
|
||||
self.queryset = self.queryset.filter(space=self.request.space)
|
||||
return super().get_queryset()
|
||||
|
||||
if not (share and self.detail):
|
||||
self.queryset = self.queryset.filter(space=self.request.space)
|
||||
self.queryset = self.queryset.filter(space=self.request.space).filter(
|
||||
Q(private=False) | (Q(private=True) & (Q(created_by=self.request.user) | Q(shared=self.request.user)))
|
||||
)
|
||||
|
||||
params = {x: self.request.GET.get(x) if len({**self.request.GET}[x]) == 1 else self.request.GET.getlist(x) for x
|
||||
in list(self.request.GET)}
|
||||
@ -790,12 +803,9 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
if self.request.GET.get('debug', False):
|
||||
return JsonResponse({
|
||||
'new': str(self.get_queryset().query),
|
||||
'old': str(old_search(request).query)
|
||||
})
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
# TODO write extensive tests for permissions
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'list':
|
||||
return RecipeOverviewSerializer
|
||||
@ -908,7 +918,7 @@ class RecipeViewSet(viewsets.ModelViewSet):
|
||||
class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingListRecipe.objects
|
||||
serializer_class = ShoppingListRecipeSerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(
|
||||
@ -924,7 +934,7 @@ class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
|
||||
class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingListEntry.objects
|
||||
serializer_class = ShoppingListEntrySerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
query_params = [
|
||||
QueryParam(name='id',
|
||||
description=_('Returns the shopping list entry with a primary key of id. Multiple values allowed.'),
|
||||
@ -963,7 +973,7 @@ class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
||||
class ShoppingListViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShoppingList.objects
|
||||
serializer_class = ShoppingListSerializer
|
||||
permission_classes = [CustomIsOwner | CustomIsShared]
|
||||
permission_classes = [(CustomIsOwner | CustomIsShared) & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(
|
||||
@ -985,7 +995,7 @@ class ShoppingListViewSet(viewsets.ModelViewSet):
|
||||
class ViewLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = ViewLog.objects
|
||||
serializer_class = ViewLogSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -996,7 +1006,7 @@ class ViewLogViewSet(viewsets.ModelViewSet):
|
||||
class CookLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = CookLog.objects
|
||||
serializer_class = CookLogSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -1006,7 +1016,7 @@ class CookLogViewSet(viewsets.ModelViewSet):
|
||||
class ImportLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = ImportLog.objects
|
||||
serializer_class = ImportLogSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -1016,7 +1026,7 @@ class ImportLogViewSet(viewsets.ModelViewSet):
|
||||
class ExportLogViewSet(viewsets.ModelViewSet):
|
||||
queryset = ExportLog.objects
|
||||
serializer_class = ExportLogSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
pagination_class = DefaultPagination
|
||||
|
||||
def get_queryset(self):
|
||||
@ -1026,7 +1036,8 @@ class ExportLogViewSet(viewsets.ModelViewSet):
|
||||
class BookmarkletImportViewSet(viewsets.ModelViewSet):
|
||||
queryset = BookmarkletImport.objects
|
||||
serializer_class = BookmarkletImportSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasScope]
|
||||
required_scopes = ['bookmarklet']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'list':
|
||||
@ -1040,7 +1051,7 @@ class BookmarkletImportViewSet(viewsets.ModelViewSet):
|
||||
class UserFileViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = UserFile.objects
|
||||
serializer_class = UserFileSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
parser_classes = [MultiPartParser]
|
||||
|
||||
def get_queryset(self):
|
||||
@ -1051,7 +1062,7 @@ class UserFileViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
class AutomationViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = Automation.objects
|
||||
serializer_class = AutomationSerializer
|
||||
permission_classes = [CustomIsUser]
|
||||
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(space=self.request.space).all()
|
||||
@ -1061,7 +1072,7 @@ class AutomationViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
class InviteLinkViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = InviteLink.objects
|
||||
serializer_class = InviteLinkSerializer
|
||||
permission_classes = [CustomIsSpaceOwner & CustomIsAdmin]
|
||||
permission_classes = [CustomIsSpaceOwner & CustomIsAdmin & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
if is_space_owner(self.request.user, self.request.space):
|
||||
@ -1074,7 +1085,7 @@ class InviteLinkViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
class CustomFilterViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
queryset = CustomFilter.objects
|
||||
serializer_class = CustomFilterSerializer
|
||||
permission_classes = [CustomIsOwner]
|
||||
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.queryset.filter(Q(created_by=self.request.user) | Q(shared=self.request.user)).filter(
|
||||
@ -1082,6 +1093,15 @@ class CustomFilterViewSet(viewsets.ModelViewSet, StandardFilterMixin):
|
||||
return super().get_queryset()
|
||||
|
||||
|
||||
class AccessTokenViewSet(viewsets.ModelViewSet):
|
||||
queryset = AccessToken.objects
|
||||
serializer_class = AccessTokenSerializer
|
||||
permission_classes = [CustomIsOwner & CustomTokenHasReadWriteScope]
|
||||
|
||||
def get_queryset(self):
|
||||
return self.queryset.filter(user=self.request.user)
|
||||
|
||||
|
||||
# -------------- DRF custom views --------------------
|
||||
|
||||
class AuthTokenThrottle(AnonRateThrottle):
|
||||
@ -1096,16 +1116,22 @@ class CustomAuthToken(ObtainAuthToken):
|
||||
context={'request': request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.validated_data['user']
|
||||
token, created = Token.objects.get_or_create(user=user)
|
||||
if token := AccessToken.objects.filter(scope__contains='read').filter(scope__contains='write').first():
|
||||
access_token = token
|
||||
else:
|
||||
access_token = AccessToken.objects.create(user=request.user, token=f'tda_{str(uuid.uuid4()).replace("-", "_")}', expires=(timezone.now() + timezone.timedelta(days=365 * 5)), scope='read write app')
|
||||
return Response({
|
||||
'token': token.key,
|
||||
'id': access_token.id,
|
||||
'token': access_token.token,
|
||||
'scope': access_token.scope,
|
||||
'expires': access_token.expires,
|
||||
'user_id': user.pk,
|
||||
})
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
# @schema(AutoSchema()) #TODO add proper schema
|
||||
@permission_classes([CustomIsUser])
|
||||
@permission_classes([CustomIsUser & CustomTokenHasReadWriteScope])
|
||||
# TODO add rate limiting
|
||||
def recipe_from_source(request):
|
||||
"""
|
||||
@ -1114,76 +1140,86 @@ def recipe_from_source(request):
|
||||
- url: url to use for importing recipe
|
||||
- data: if no url is given recipe is imported from provided source data
|
||||
- (optional) bookmarklet: id of bookmarklet import to use, overrides URL and data attributes
|
||||
:return: JsonResponse containing the parsed json, original html,json and images
|
||||
:return: JsonResponse containing the parsed json and images
|
||||
"""
|
||||
scrape = None
|
||||
serializer = RecipeFromSourceSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
try:
|
||||
if bookmarklet := BookmarkletImport.objects.filter(pk=serializer.validated_data['bookmarklet']).first():
|
||||
serializer.validated_data['url'] = bookmarklet.url
|
||||
serializer.validated_data['data'] = bookmarklet.html
|
||||
bookmarklet.delete()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# headers to use for request to external sites
|
||||
external_request_headers = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7"}
|
||||
if (b_pk := serializer.validated_data.get('bookmarklet', None)) and (bookmarklet := BookmarkletImport.objects.filter(pk=b_pk).first()):
|
||||
serializer.validated_data['url'] = bookmarklet.url
|
||||
serializer.validated_data['data'] = bookmarklet.html
|
||||
bookmarklet.delete()
|
||||
|
||||
if not 'url' in serializer.validated_data and not 'data' in serializer.validated_data:
|
||||
url = serializer.validated_data.get('url', None)
|
||||
data = unquote(serializer.validated_data.get('data', None))
|
||||
if not url and not data:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('Nothing to do.')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# in manual mode request complete page to return it later
|
||||
if 'url' in serializer.validated_data:
|
||||
if re.match('^(https?://)?(www\.youtube\.com|youtu\.be)/.+$', serializer.validated_data['url']):
|
||||
if validators.url(serializer.validated_data['url'], public=True):
|
||||
elif url and not data:
|
||||
if re.match('^(https?://)?(www\.youtube\.com|youtu\.be)/.+$', url):
|
||||
if validators.url(url, public=True):
|
||||
return Response({
|
||||
'recipe_json': get_from_youtube_scraper(serializer.validated_data['url'], request),
|
||||
'recipe_tree': '',
|
||||
'recipe_html': '',
|
||||
'recipe_json': get_from_youtube_scraper(url, request),
|
||||
# 'recipe_tree': '',
|
||||
# 'recipe_html': '',
|
||||
'recipe_images': [],
|
||||
}, status=status.HTTP_200_OK)
|
||||
try:
|
||||
if validators.url(serializer.validated_data['url'], public=True):
|
||||
serializer.validated_data['data'] = requests.get(serializer.validated_data['url'], headers=external_request_headers).content
|
||||
else:
|
||||
else:
|
||||
try:
|
||||
if validators.url(url, public=True):
|
||||
scrape = scrape_me(url_path=url, wild_mode=True)
|
||||
|
||||
else:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('Invalid Url')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
except NoSchemaFoundInWildMode:
|
||||
pass
|
||||
except requests.exceptions.ConnectionError:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('Invalid Url')
|
||||
'msg': _('Connection Refused.')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
except requests.exceptions.ConnectionError:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('Connection Refused.')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
except requests.exceptions.MissingSchema:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('Bad URL Schema.')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
except requests.exceptions.MissingSchema:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('Bad URL Schema.')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
try:
|
||||
json.loads(data)
|
||||
data = "<script type='application/ld+json'>" + data + "</script>"
|
||||
except JSONDecodeError:
|
||||
pass
|
||||
scrape = text_scraper(text=data, url=url)
|
||||
if not url and (found_url := scrape.schema.data.get('url', None)):
|
||||
scrape = text_scraper(text=data, url=found_url)
|
||||
|
||||
recipe_json, recipe_tree, recipe_html, recipe_images = get_recipe_from_source(serializer.validated_data['data'], serializer.validated_data['url'], request)
|
||||
if len(recipe_tree) == 0 and len(recipe_json) == 0:
|
||||
if scrape:
|
||||
return Response({
|
||||
'recipe_json': helper.get_from_scraper(scrape, request),
|
||||
# 'recipe_tree': recipe_tree,
|
||||
# 'recipe_html': recipe_html,
|
||||
'recipe_images': list(dict.fromkeys(get_images_from_soup(scrape.soup, url))),
|
||||
}, status=status.HTTP_200_OK)
|
||||
|
||||
else:
|
||||
return Response({
|
||||
'error': True,
|
||||
'msg': _('No usable data could be found.')
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
return Response({
|
||||
'recipe_json': recipe_json,
|
||||
'recipe_tree': recipe_tree,
|
||||
'recipe_html': recipe_html,
|
||||
'recipe_images': list(dict.fromkeys(recipe_images)),
|
||||
}, status=status.HTTP_200_OK)
|
||||
else:
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
# @schema(AutoSchema()) #TODO add proper schema
|
||||
@permission_classes([CustomIsAdmin])
|
||||
@permission_classes([CustomIsAdmin & CustomTokenHasReadWriteScope])
|
||||
# TODO add rate limiting
|
||||
def reset_food_inheritance(request):
|
||||
"""
|
||||
@ -1199,7 +1235,7 @@ def reset_food_inheritance(request):
|
||||
|
||||
@api_view(['GET'])
|
||||
# @schema(AutoSchema()) #TODO add proper schema
|
||||
@permission_classes([CustomIsAdmin])
|
||||
@permission_classes([CustomIsAdmin & CustomTokenHasReadWriteScope])
|
||||
# TODO add rate limiting
|
||||
def switch_active_space(request, space_id):
|
||||
"""
|
||||
@ -1219,7 +1255,7 @@ def switch_active_space(request, space_id):
|
||||
|
||||
@api_view(['GET'])
|
||||
# @schema(AutoSchema()) #TODO add proper schema
|
||||
@permission_classes([CustomIsUser])
|
||||
@permission_classes([CustomIsUser & CustomTokenHasReadWriteScope])
|
||||
def download_file(request, file_id):
|
||||
"""
|
||||
function to download a user file securely (wrapping as zip to prevent any context based XSS problems)
|
||||
@ -1242,6 +1278,35 @@ def download_file(request, file_id):
|
||||
return Response({}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
# @schema(AutoSchema()) #TODO add proper schema
|
||||
@permission_classes([CustomIsUser & CustomTokenHasReadWriteScope])
|
||||
def import_files(request):
|
||||
"""
|
||||
function to handle files passed by application importer
|
||||
"""
|
||||
limit, msg = above_space_limit(request.space)
|
||||
if limit:
|
||||
return Response({'error': msg}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
form = ImportForm(request.POST, request.FILES)
|
||||
if form.is_valid() and request.FILES != {}:
|
||||
try:
|
||||
integration = get_integration(request, form.cleaned_data['type'])
|
||||
|
||||
il = ImportLog.objects.create(type=form.cleaned_data['type'], created_by=request.user, space=request.space)
|
||||
files = []
|
||||
for f in request.FILES.getlist('files'):
|
||||
files.append({'file': io.BytesIO(f.read()), 'name': f.name})
|
||||
t = threading.Thread(target=integration.do_import, args=[files, il, form.cleaned_data['duplicates']])
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
return Response({'import_id': il.pk}, status=status.HTTP_200_OK)
|
||||
except NotImplementedError:
|
||||
return Response({'error': True, 'msg': _('Importing is not implemented for this provider')}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
def get_recipe_provider(recipe):
|
||||
if recipe.storage.method == Storage.DROPBOX:
|
||||
return Dropbox
|
||||
|
@ -1,12 +1,15 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import ngettext
|
||||
from django_tables2 import RequestConfig
|
||||
from oauth2_provider.models import AccessToken
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from cookbook.forms import BatchEditForm, SyncForm
|
||||
@ -115,34 +118,12 @@ def import_url(request):
|
||||
messages.add_message(request, messages.WARNING, msg)
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
if (api_token := Token.objects.filter(user=request.user).first()) is None:
|
||||
api_token = Token.objects.create(user=request.user)
|
||||
if (api_token := AccessToken.objects.filter(user=request.user, scope='bookmarklet').first()) is None:
|
||||
api_token = AccessToken.objects.create(user=request.user, scope='bookmarklet', expires=(timezone.now() + timezone.timedelta(days=365*10)), token=f'tda_{str(uuid.uuid4()).replace("-","_")}')
|
||||
|
||||
bookmarklet_import_id = -1
|
||||
if 'id' in request.GET:
|
||||
if bookmarklet_import := BookmarkletImport.objects.filter(id=request.GET['id']).first():
|
||||
bookmarklet_import_id = bookmarklet_import.pk
|
||||
|
||||
return render(request, 'url_import.html', {'api_token': api_token, 'bookmarklet_import_id': bookmarklet_import_id})
|
||||
|
||||
|
||||
class Object(object):
|
||||
pass
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def statistics(request):
|
||||
counts = Object()
|
||||
counts.recipes = Recipe.objects.filter(space=request.space).count()
|
||||
counts.keywords = Keyword.objects.filter(space=request.space).count()
|
||||
counts.recipe_import = RecipeImport.objects.filter(space=request.space).count()
|
||||
counts.units = Unit.objects.filter(space=request.space).count()
|
||||
counts.ingredients = Food.objects.filter(space=request.space).count()
|
||||
counts.comments = Comment.objects.filter(recipe__space=request.space).count()
|
||||
|
||||
counts.recipes_internal = Recipe.objects.filter(internal=True, space=request.space).count()
|
||||
counts.recipes_external = counts.recipes - counts.recipes_internal
|
||||
|
||||
counts.recipes_no_keyword = Recipe.objects.filter(keywords=None, space=request.space).count()
|
||||
|
||||
return render(request, 'stats.html', {'counts': counts})
|
||||
return render(request, 'url_import.html', {'api_token': api_token, 'bookmarklet_import_id': bookmarklet_import_id})
|
@ -82,42 +82,6 @@ def get_integration(request, export_type):
|
||||
return Cookmate(request, export_type)
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def import_recipe(request):
|
||||
limit, msg = above_space_limit(request.space)
|
||||
if limit:
|
||||
messages.add_message(request, messages.WARNING, msg)
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
if request.method == "POST":
|
||||
form = ImportForm(request.POST, request.FILES)
|
||||
if form.is_valid() and request.FILES != {}:
|
||||
try:
|
||||
integration = get_integration(request, form.cleaned_data['type'])
|
||||
|
||||
il = ImportLog.objects.create(type=form.cleaned_data['type'], created_by=request.user, space=request.space)
|
||||
files = []
|
||||
for f in request.FILES.getlist('files'):
|
||||
files.append({'file': BytesIO(f.read()), 'name': f.name})
|
||||
t = threading.Thread(target=integration.do_import, args=[files, il, form.cleaned_data['duplicates']])
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
return JsonResponse({'import_id': il.pk})
|
||||
except NotImplementedError:
|
||||
return JsonResponse(
|
||||
{
|
||||
'error': True,
|
||||
'msg': _('Importing is not implemented for this provider')
|
||||
},
|
||||
status=400
|
||||
)
|
||||
else:
|
||||
form = ImportForm()
|
||||
|
||||
return render(request, 'import.html', {'form': form})
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def export_recipe(request):
|
||||
if request.method == "POST":
|
||||
|
@ -1,5 +1,6 @@
|
||||
import os
|
||||
import re
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
@ -11,28 +12,21 @@ from django.contrib.auth.forms import PasswordChangeForm
|
||||
from django.contrib.auth.models import Group
|
||||
from django.contrib.auth.password_validation import validate_password
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Avg, Q
|
||||
from django.db.models.functions import Lower
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from django_tables2 import RequestConfig
|
||||
from rest_framework.authtoken.models import Token
|
||||
from oauth2_provider.models import AccessToken
|
||||
|
||||
from cookbook.filters import RecipeFilter
|
||||
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, ShoppingPreferenceForm,
|
||||
SpaceCreateForm, SpaceJoinForm, SpacePreferenceForm, User,
|
||||
SpaceCreateForm, SpaceJoinForm, User,
|
||||
UserCreateForm, UserNameForm, UserPreference, UserPreferenceForm)
|
||||
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
||||
from cookbook.models import (Comment, CookLog, Food, InviteLink, Keyword,
|
||||
MealPlan, RecipeImport, SearchFields, SearchPreference, ShareLink,
|
||||
Space, Unit, ViewLog, UserSpace)
|
||||
from cookbook.tables import (CookLogTable, InviteLinkTable, RecipeTable, RecipeTableSmall,
|
||||
ViewLogTable)
|
||||
from cookbook.views.data import Object
|
||||
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink,
|
||||
Space, ViewLog, UserSpace)
|
||||
from cookbook.tables import (CookLogTable, ViewLogTable)
|
||||
from recipes.version import BUILD_REF, VERSION_NUMBER
|
||||
|
||||
|
||||
@ -58,34 +52,7 @@ def index(request):
|
||||
# TODO need to deprecate
|
||||
def search(request):
|
||||
if has_group_permission(request.user, ('guest',)):
|
||||
if request.user.userpreference.search_style == UserPreference.NEW:
|
||||
return search_v2(request)
|
||||
f = RecipeFilter(request.GET,
|
||||
queryset=Recipe.objects.filter(space=request.space).all().order_by(
|
||||
Lower('name').asc()),
|
||||
space=request.space)
|
||||
if request.user.userpreference.search_style == UserPreference.LARGE:
|
||||
table = RecipeTable(f.qs)
|
||||
else:
|
||||
table = RecipeTableSmall(f.qs)
|
||||
RequestConfig(request, paginate={'per_page': 25}).configure(table)
|
||||
|
||||
if request.GET == {} and request.user.userpreference.show_recent:
|
||||
qs = Recipe.objects.filter(viewlog__created_by=request.user).filter(
|
||||
space=request.space).order_by('-viewlog__created_at').all()
|
||||
|
||||
recent_list = []
|
||||
for r in qs:
|
||||
if r not in recent_list:
|
||||
recent_list.append(r)
|
||||
if len(recent_list) >= 5:
|
||||
break
|
||||
|
||||
last_viewed = RecipeTable(recent_list)
|
||||
else:
|
||||
last_viewed = None
|
||||
|
||||
return render(request, 'index.html', {'recipes': table, 'filter': f, 'last_viewed': last_viewed})
|
||||
return render(request, 'search.html', {})
|
||||
else:
|
||||
if request.user.is_authenticated:
|
||||
return HttpResponseRedirect(reverse('view_no_group'))
|
||||
@ -93,11 +60,6 @@ def search(request):
|
||||
return HttpResponseRedirect(reverse('account_login') + '?next=' + request.path)
|
||||
|
||||
|
||||
@group_required('guest')
|
||||
def search_v2(request):
|
||||
return render(request, 'search.html', {})
|
||||
|
||||
|
||||
def no_groups(request):
|
||||
return render(request, 'no_groups_info.html')
|
||||
|
||||
@ -127,14 +89,14 @@ def space_overview(request):
|
||||
if join_form.is_valid():
|
||||
return HttpResponseRedirect(reverse('view_invite', args=[join_form.cleaned_data['token']]))
|
||||
else:
|
||||
if settings.SOCIAL_DEFAULT_ACCESS:
|
||||
user_space = UserSpace.objects.create(space=Space.objects.first(), user=request.user, active=True)
|
||||
if settings.SOCIAL_DEFAULT_ACCESS and len(request.user.userspace_set.all()) == 0:
|
||||
user_space = UserSpace.objects.create(space=Space.objects.first(), user=request.user, active=False)
|
||||
user_space.groups.add(Group.objects.filter(name=settings.SOCIAL_DEFAULT_GROUP).get())
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
if 'signup_token' in request.session:
|
||||
return HttpResponseRedirect(reverse('view_invite', args=[request.session.pop('signup_token', '')]))
|
||||
|
||||
create_form = SpaceCreateForm(initial={'name': f'{request.user.username}\'s Space'})
|
||||
create_form = SpaceCreateForm(initial={'name': f'{request.user.get_user_display_name()}\'s Space'})
|
||||
join_form = SpaceJoinForm()
|
||||
|
||||
return render(request, 'space_overview.html', {'create_form': create_form, 'join_form': join_form})
|
||||
@ -190,18 +152,6 @@ def recipe_view(request, pk, share=None):
|
||||
|
||||
comment_form = CommentForm()
|
||||
|
||||
user_servings = None
|
||||
if request.user.is_authenticated:
|
||||
user_servings = CookLog.objects.filter(
|
||||
recipe=recipe,
|
||||
created_by=request.user,
|
||||
servings__gt=0,
|
||||
space=request.space,
|
||||
).all().aggregate(Avg('servings'))['servings__avg']
|
||||
|
||||
if not user_servings:
|
||||
user_servings = 0
|
||||
|
||||
if request.user.is_authenticated:
|
||||
if not ViewLog.objects.filter(recipe=recipe, created_by=request.user,
|
||||
created_at__gt=(timezone.now() - timezone.timedelta(minutes=5)),
|
||||
@ -209,8 +159,7 @@ def recipe_view(request, pk, share=None):
|
||||
ViewLog.objects.create(recipe=recipe, created_by=request.user, space=request.space)
|
||||
|
||||
return render(request, 'recipe_view.html',
|
||||
{'recipe': recipe, 'comments': comments, 'comment_form': comment_form, 'share': share,
|
||||
'user_servings': user_servings})
|
||||
{'recipe': recipe, 'comments': comments, 'comment_form': comment_form, 'share': share, })
|
||||
|
||||
|
||||
@group_required('user')
|
||||
@ -228,6 +177,20 @@ def supermarket(request):
|
||||
return render(request, 'supermarket.html', {})
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def view_profile(request, user_id):
|
||||
return render(request, 'profile.html', {})
|
||||
|
||||
|
||||
@group_required('guest')
|
||||
def user_settings(request):
|
||||
if request.space.demo:
|
||||
messages.add_message(request, messages.ERROR, _('This feature is not available in the demo version!'))
|
||||
return redirect('index')
|
||||
|
||||
return render(request, 'user_settings.html', {})
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def ingredient_editor(request):
|
||||
template_vars = {'food_id': -1, 'unit_id': -1}
|
||||
@ -241,74 +204,17 @@ def ingredient_editor(request):
|
||||
return render(request, 'ingredient_editor.html', template_vars)
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def meal_plan_entry(request, pk):
|
||||
plan = MealPlan.objects.filter(space=request.space).get(pk=pk)
|
||||
|
||||
if plan.created_by != request.user and plan.shared != request.user:
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('index'))
|
||||
|
||||
same_day_plan = MealPlan.objects \
|
||||
.filter(date=plan.date, space=request.space) \
|
||||
.exclude(pk=plan.pk) \
|
||||
.filter(Q(created_by=request.user) | Q(shared=request.user)) \
|
||||
.order_by('meal_type').all()
|
||||
|
||||
return render(request, 'meal_plan_entry.html', {'plan': plan, 'same_day_plan': same_day_plan})
|
||||
|
||||
|
||||
@group_required('guest')
|
||||
def user_settings(request):
|
||||
def shopping_settings(request):
|
||||
if request.space.demo:
|
||||
messages.add_message(request, messages.ERROR, _('This feature is not available in the demo version!'))
|
||||
return redirect('index')
|
||||
|
||||
up = request.user.userpreference
|
||||
sp = request.user.searchpreference
|
||||
search_error = False
|
||||
active_tab = 'account'
|
||||
|
||||
user_name_form = UserNameForm(instance=request.user)
|
||||
|
||||
if request.method == "POST":
|
||||
if 'preference_form' in request.POST:
|
||||
active_tab = 'preferences'
|
||||
form = UserPreferenceForm(request.POST, prefix='preference', space=request.space)
|
||||
if form.is_valid():
|
||||
if not up:
|
||||
up = UserPreference(user=request.user)
|
||||
|
||||
up.theme = form.cleaned_data['theme']
|
||||
up.nav_color = form.cleaned_data['nav_color']
|
||||
up.default_unit = form.cleaned_data['default_unit']
|
||||
up.default_page = form.cleaned_data['default_page']
|
||||
up.show_recent = form.cleaned_data['show_recent']
|
||||
up.search_style = form.cleaned_data['search_style']
|
||||
up.plan_share.set(form.cleaned_data['plan_share'])
|
||||
up.ingredient_decimals = form.cleaned_data['ingredient_decimals'] # noqa: E501
|
||||
up.comments = form.cleaned_data['comments']
|
||||
up.use_fractions = form.cleaned_data['use_fractions']
|
||||
up.use_kj = form.cleaned_data['use_kj']
|
||||
up.sticky_navbar = form.cleaned_data['sticky_navbar']
|
||||
up.left_handed = form.cleaned_data['left_handed']
|
||||
|
||||
up.save()
|
||||
|
||||
elif 'user_name_form' in request.POST:
|
||||
user_name_form = UserNameForm(request.POST, prefix='name')
|
||||
if user_name_form.is_valid():
|
||||
request.user.first_name = user_name_form.cleaned_data['first_name']
|
||||
request.user.last_name = user_name_form.cleaned_data['last_name']
|
||||
request.user.save()
|
||||
|
||||
elif 'password_form' in request.POST:
|
||||
password_form = PasswordChangeForm(request.user, request.POST)
|
||||
if password_form.is_valid():
|
||||
user = password_form.save()
|
||||
update_session_auth_hash(request, user)
|
||||
|
||||
elif 'search_form' in request.POST:
|
||||
if 'search_form' in request.POST:
|
||||
active_tab = 'search'
|
||||
search_form = SearchPreferenceForm(request.POST, prefix='search')
|
||||
if search_form.is_valid():
|
||||
@ -357,39 +263,13 @@ def user_settings(request):
|
||||
sp.lookup = True
|
||||
sp.unaccent.set(SearchFields.objects.all())
|
||||
# full text on food is very slow, add search_vector field and index it (including Admin functions and postsave signal to rebuild index)
|
||||
sp.icontains.set([SearchFields.objects.get(name__in=['Name', 'Ingredients'])])
|
||||
sp.icontains.set([SearchFields.objects.get(name='Name')])
|
||||
sp.istartswith.set([SearchFields.objects.get(name='Name')])
|
||||
sp.trigram.clear()
|
||||
sp.fulltext.set(SearchFields.objects.filter(name__in=['Ingredients']))
|
||||
sp.trigram_threshold = 0.2
|
||||
|
||||
sp.save()
|
||||
elif 'shopping_form' in request.POST:
|
||||
shopping_form = ShoppingPreferenceForm(request.POST, prefix='shopping')
|
||||
if shopping_form.is_valid():
|
||||
if not up:
|
||||
up = UserPreference(user=request.user)
|
||||
|
||||
up.shopping_share.set(shopping_form.cleaned_data['shopping_share'])
|
||||
up.mealplan_autoadd_shopping = shopping_form.cleaned_data['mealplan_autoadd_shopping']
|
||||
up.mealplan_autoexclude_onhand = shopping_form.cleaned_data['mealplan_autoexclude_onhand']
|
||||
up.mealplan_autoinclude_related = shopping_form.cleaned_data['mealplan_autoinclude_related']
|
||||
up.shopping_auto_sync = shopping_form.cleaned_data['shopping_auto_sync']
|
||||
up.filter_to_supermarket = shopping_form.cleaned_data['filter_to_supermarket']
|
||||
up.default_delay = shopping_form.cleaned_data['default_delay']
|
||||
up.shopping_recent_days = shopping_form.cleaned_data['shopping_recent_days']
|
||||
up.shopping_add_onhand = shopping_form.cleaned_data['shopping_add_onhand']
|
||||
up.csv_delim = shopping_form.cleaned_data['csv_delim']
|
||||
up.csv_prefix = shopping_form.cleaned_data['csv_prefix']
|
||||
if up.shopping_auto_sync < settings.SHOPPING_MIN_AUTOSYNC_INTERVAL:
|
||||
up.shopping_auto_sync = settings.SHOPPING_MIN_AUTOSYNC_INTERVAL
|
||||
up.save()
|
||||
if up:
|
||||
preference_form = UserPreferenceForm(instance=up, space=request.space)
|
||||
shopping_form = ShoppingPreferenceForm(instance=up)
|
||||
else:
|
||||
preference_form = UserPreferenceForm(space=request.space)
|
||||
shopping_form = ShoppingPreferenceForm(space=request.space)
|
||||
|
||||
fields_searched = len(sp.icontains.all()) + len(sp.istartswith.all()) + len(sp.trigram.all()) + len(
|
||||
sp.fulltext.all())
|
||||
@ -398,9 +278,6 @@ def user_settings(request):
|
||||
elif not search_error:
|
||||
search_form = SearchPreferenceForm()
|
||||
|
||||
if (api_token := Token.objects.filter(user=request.user).first()) is None:
|
||||
api_token = Token.objects.create(user=request.user)
|
||||
|
||||
# these fields require postgresql - just disable them if postgresql isn't available
|
||||
if not settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
|
||||
'django.db.backends.postgresql']:
|
||||
@ -410,12 +287,7 @@ def user_settings(request):
|
||||
search_form.fields['fulltext'].disabled = True
|
||||
|
||||
return render(request, 'settings.html', {
|
||||
'preference_form': preference_form,
|
||||
'user_name_form': user_name_form,
|
||||
'api_token': api_token,
|
||||
'search_form': search_form,
|
||||
'shopping_form': shopping_form,
|
||||
'active_tab': active_tab
|
||||
})
|
||||
|
||||
|
||||
@ -496,8 +368,9 @@ def invite_link(request, token):
|
||||
|
||||
if link := InviteLink.objects.filter(valid_until__gte=datetime.today(), used_by=None, uuid=token).first():
|
||||
if request.user.is_authenticated and not request.user.userspace_set.filter(space=link.space).exists():
|
||||
link.used_by = request.user
|
||||
link.save()
|
||||
if not link.reusable:
|
||||
link.used_by = request.user
|
||||
link.save()
|
||||
|
||||
user_space = UserSpace.objects.create(user=request.user, space=link.space, active=False)
|
||||
|
||||
@ -519,6 +392,9 @@ def invite_link(request, token):
|
||||
|
||||
@group_required('admin')
|
||||
def space_manage(request, space_id):
|
||||
if request.space.demo:
|
||||
messages.add_message(request, messages.ERROR, _('This feature is not available in the demo version!'))
|
||||
return redirect('index')
|
||||
space = get_object_or_404(Space, id=space_id)
|
||||
switch_user_active_space(request.user, space)
|
||||
return render(request, 'space_manage.html', {})
|
||||
|
44
docs/system/migration_sqlite-postgres.md
Normal file
44
docs/system/migration_sqlite-postgres.md
Normal file
@ -0,0 +1,44 @@
|
||||
# How to migrate from sqlite3 database to postgresql
|
||||
This migration was written while using the unraid template (docker) for TandoorRecipes, version 1.3.0.
|
||||
While some commands are unraid specific, it should in general work for any setup.
|
||||
|
||||
1. Make a backup of your `/mnt/user/appdata/recipes` dir.
|
||||
|
||||
2. Without changing any settings, get a shell into the TandoorRecipes docker through the Web-UI or by running `docker exec -it TandoorRecipes /bin/sh`
|
||||
```cmd
|
||||
cd /opt/recipes
|
||||
./venv/bin/python manage.py export -a > /data/dump.json
|
||||
```
|
||||
|
||||
3. Create a Postgresql database (With a new user & database for recipes)
|
||||
|
||||
I used the `postgresql14` template.
|
||||
|
||||
```cmd
|
||||
psql -U postgres
|
||||
postgres=# create database tandoor;
|
||||
postgres=# create user tandoor with encrypted password 'yoursupersecretpassworddontusethisone';
|
||||
postgres=# grant all privileges on database tandoor to tandoor;
|
||||
```
|
||||
|
||||
4. Now its time to change some enviourment variables in TandoorRecipes template:
|
||||
```env
|
||||
DB_ENGINE=django.db.backends.postgresql # Database Engine, previous value: `django.db.backends.sqlite3`
|
||||
POSTGRES_HOST=<Your unraid host ip> # PostgreSQL Host
|
||||
POSTGRES_PORT=5432 # PostgreSQL Host
|
||||
POSTGRES_USER=tandoor # PostgreSQL User
|
||||
POSTGRES_PASSWORD=yoursupersecretpassworddyoudidntcopy # PostgreSQL Password
|
||||
POSTGRES_DB=tandoor # Database, previous value: `/data/recipes.db`
|
||||
```
|
||||
|
||||
5. Save it, and start the container once.
|
||||
|
||||
It will perform all database migrations once for the postgresql database.
|
||||
|
||||
6. Get a shell into the docker through the WEB-UI or by running `docker exec -it TandoorRecipes /bin/sh`
|
||||
```cmd
|
||||
cd /opt/recipes
|
||||
./venv/bin/python manage.py import /data/dump.json
|
||||
```
|
||||
|
||||
7. Enjoy your new fuzzy search options and SLIGHTLY performance increase!
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-26 12:09+0200\n"
|
||||
"POT-Creation-Date: 2022-07-12 19:20+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -52,6 +52,9 @@ SHOPPING_MIN_AUTOSYNC_INTERVAL = int(os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL',
|
||||
|
||||
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS').split(',') if os.getenv('ALLOWED_HOSTS') else ['*']
|
||||
|
||||
if os.getenv('CSRF_TRUSTED_ORIGINS'):
|
||||
CSRF_TRUSTED_ORIGINS = os.getenv('CSRF_TRUSTED_ORIGINS').split(',')
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
LOGIN_REDIRECT_URL = "index"
|
||||
@ -96,10 +99,10 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.postgres',
|
||||
'oauth2_provider',
|
||||
'django_prometheus',
|
||||
'django_tables2',
|
||||
'corsheaders',
|
||||
'django_filters',
|
||||
'crispy_forms',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
@ -233,10 +236,17 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
OAUTH2_PROVIDER = {
|
||||
'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'bookmarklet': 'only access to bookmarklet'}
|
||||
}
|
||||
READ_SCOPE = 'read'
|
||||
WRITE_SCOPE = 'write'
|
||||
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
@ -409,6 +419,8 @@ if os.getenv('S3_ACCESS_KEY', ''):
|
||||
|
||||
if os.getenv('S3_ENDPOINT_URL', ''):
|
||||
AWS_S3_ENDPOINT_URL = os.getenv('S3_ENDPOINT_URL', '')
|
||||
if os.getenv('S3_CUSTOM_DOMAIN', ''):
|
||||
AWS_S3_CUSTOM_DOMAIN = os.getenv('S3_CUSTOM_DOMAIN', '')
|
||||
|
||||
MEDIA_URL = os.getenv('MEDIA_URL', '/media/')
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles")
|
||||
|
@ -1,13 +1,13 @@
|
||||
Django==4.0.6
|
||||
Django==4.0.7
|
||||
cryptography==37.0.2
|
||||
django-annoying==0.10.6
|
||||
django-autocomplete-light==3.9.4
|
||||
django-cleanup==6.0.0
|
||||
django-crispy-forms==1.14.0
|
||||
django-filter==22.1
|
||||
django-tables2==2.4.1
|
||||
djangorestframework==3.13.1
|
||||
drf-writable-nested==0.6.3
|
||||
drf-writable-nested==0.6.4
|
||||
django-oauth-toolkit==2.1.0
|
||||
bleach==5.0.1
|
||||
bleach-allowlist==1.0.3
|
||||
gunicorn==20.1.0
|
||||
@ -20,7 +20,7 @@ requests==2.28.1
|
||||
six==1.16.0
|
||||
webdavclient3==3.14.6
|
||||
whitenoise==6.2.0
|
||||
icalendar==4.0.9
|
||||
icalendar==4.1.0
|
||||
pyyaml==6.0
|
||||
uritemplate==4.1.1
|
||||
beautifulsoup4==4.11.1
|
||||
@ -29,7 +29,7 @@ Jinja2==3.1.2
|
||||
django-webpack-loader==1.5.0
|
||||
git+https://github.com/ierror/django-js-reverse@7cab78c4531780ab4b32033d5104ccd5be1a246a
|
||||
django-allauth==0.51.0
|
||||
recipe-scrapers==14.6.0
|
||||
recipe-scrapers==14.11.0
|
||||
django-scopes==1.2.0.post1
|
||||
pytest==7.1.2
|
||||
pytest-django==4.5.2
|
||||
@ -39,7 +39,7 @@ django-storages==1.12.3
|
||||
boto3==1.24.21
|
||||
django-prometheus==2.2.0
|
||||
django-hCaptcha==0.2.0
|
||||
python-ldap==3.4.0
|
||||
python-ldap==3.4.2
|
||||
django-auth-ldap==4.1.0
|
||||
pytest-factoryboy==2.5.0
|
||||
pyppeteer==1.0.2
|
||||
|
@ -69,7 +69,9 @@
|
||||
v-if="recipe.imported !== undefined && recipe.imported"
|
||||
target="_blank">{{
|
||||
recipe.recipe_name
|
||||
}}</a> <a target="_blank" :href="`${resolveDjangoUrl('view_search') }?query=${recipe.recipe_name}`" v-else>{{ recipe.recipe_name }}</a>
|
||||
}}</a> <a target="_blank"
|
||||
:href="`${resolveDjangoUrl('view_search') }?query=${recipe.recipe_name}`"
|
||||
v-else>{{ recipe.recipe_name }}</a>
|
||||
<b-badge class="float-right text-white">{{ index + 1 }}</b-badge>
|
||||
</h5>
|
||||
<p class="mb-0">
|
||||
@ -212,16 +214,19 @@ export default {
|
||||
}
|
||||
if (out.info !== '') {
|
||||
let items = out.info.split(/:(.*)/s)[1]
|
||||
items = items.split(",")
|
||||
out.duplicates_total = items.length
|
||||
out.recipes.forEach((recipe) => {
|
||||
recipe.imported = true
|
||||
items.forEach((item) => {
|
||||
if (recipe.recipe_name === item.trim()) {
|
||||
recipe.imported = false
|
||||
}
|
||||
if (items !== undefined) {
|
||||
items = items.split(",")
|
||||
out.duplicates_total = items.length
|
||||
out.recipes.forEach((recipe) => {
|
||||
recipe.imported = true
|
||||
items.forEach((item) => {
|
||||
if (recipe.recipe_name === item.trim()) {
|
||||
recipe.imported = false
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
if (out.imported_total > 0) {
|
||||
out.recipes.forEach((recipe) => {
|
||||
|
@ -461,8 +461,8 @@ export default {
|
||||
recent_urls: [],
|
||||
source_data: '',
|
||||
recipe_json: undefined,
|
||||
recipe_html: undefined,
|
||||
recipe_tree: undefined,
|
||||
// recipe_html: undefined,
|
||||
// recipe_tree: undefined,
|
||||
recipe_images: [],
|
||||
imported_recipes: [],
|
||||
failed_imports: [],
|
||||
@ -593,9 +593,9 @@ export default {
|
||||
}
|
||||
|
||||
// reset all variables
|
||||
this.recipe_html = undefined
|
||||
// this.recipe_html = undefined
|
||||
this.recipe_json = undefined
|
||||
this.recipe_tree = undefined
|
||||
// this.recipe_tree = undefined
|
||||
this.recipe_images = []
|
||||
|
||||
// load recipe
|
||||
@ -621,8 +621,8 @@ export default {
|
||||
return x
|
||||
})
|
||||
|
||||
this.recipe_tree = response.data['recipe_tree'];
|
||||
this.recipe_html = response.data['recipe_html'];
|
||||
// this.recipe_tree = response.data['recipe_tree'];
|
||||
// this.recipe_html = response.data['recipe_html'];
|
||||
this.recipe_images = response.data['recipe_images'] !== undefined ? response.data['recipe_images'] : [];
|
||||
|
||||
if (!silent) {
|
||||
@ -695,7 +695,7 @@ export default {
|
||||
`localStorage.setItem("importURL", "${localStorage.getItem('BASE_PATH')}${this.resolveDjangoUrl('api:bookmarkletimport-list')}");` +
|
||||
`localStorage.setItem("redirectURL", "${localStorage.getItem('BASE_PATH')}${this.resolveDjangoUrl('data_import_url')}");` +
|
||||
`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)}` +
|
||||
`document.body.appendChild(document.createElement("script")).src="${localStorage.getItem('BASE_PATH')}${resolveDjangoStatic('/js/bookmarklet_v3.js')}?r="+Math.floor(Math.random()*999999999)}` +
|
||||
`})()`
|
||||
},
|
||||
},
|
||||
|
45
vue/src/apps/ProfileView/ProfileView.vue
Normal file
45
vue/src/apps/ProfileView/ProfileView.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div id="app" class="col-12 col-xl-8 col-lg-10 offset-xl-2 offset-lg-1 offset">
|
||||
<div class="col-12 col-xl-8 col-lg-10 offset-xl-2 offset-lg-1">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue"
|
||||
import { BootstrapVue } from "bootstrap-vue"
|
||||
|
||||
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||
import { ApiApiFactory } from "@/utils/openapi/api"
|
||||
import CookbookSlider from "@/components/CookbookSlider"
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import { StandardToasts, ApiMixin } from "@/utils/utils"
|
||||
|
||||
Vue.use(BootstrapVue)
|
||||
|
||||
export default {
|
||||
name: "ProfileView",
|
||||
mixins: [ApiMixin],
|
||||
components: { },
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
18
vue/src/apps/ProfileView/main.js
Normal file
18
vue/src/apps/ProfileView/main.js
Normal file
@ -0,0 +1,18 @@
|
||||
import Vue from 'vue'
|
||||
import App from './ProfileView.vue'
|
||||
import i18n from '@/i18n'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
// TODO move this and other default stuff to centralized JS file (verify nothing breaks)
|
||||
let publicPath = localStorage.STATIC_URL + 'vue/'
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
publicPath = 'http://localhost:8080/'
|
||||
}
|
||||
export default __webpack_public_path__ = publicPath // eslint-disable-line
|
||||
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
@ -188,10 +188,31 @@
|
||||
</b-form-checkbox>
|
||||
|
||||
<br/>
|
||||
<label for="id_name"> {{ $t("Imported_From") }}</label>
|
||||
<label> {{ $t("Imported_From") }}</label>
|
||||
<b-form-input v-model="recipe.source_url">
|
||||
|
||||
</b-form-input>
|
||||
|
||||
<br/>
|
||||
<label> {{ $t("Private_Recipe") }}</label>
|
||||
<b-form-checkbox v-model="recipe.private">
|
||||
{{ $t('Private_Recipe_Help') }}
|
||||
</b-form-checkbox>
|
||||
|
||||
<br/>
|
||||
<label> {{ $t("Share") }}</label>
|
||||
<generic-multiselect
|
||||
@change="recipe.shared = $event.val"
|
||||
parent_variable="recipe.shared"
|
||||
:initial_selection="recipe.shared"
|
||||
:label="'display_name'"
|
||||
:model="Models.USER_NAME"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
v-bind:placeholder="$t('Share')"
|
||||
:limit="25"
|
||||
></generic-multiselect>
|
||||
|
||||
|
||||
</b-collapse>
|
||||
</div>
|
||||
</div>
|
||||
@ -577,9 +598,9 @@
|
||||
<div class="col-md-12">
|
||||
<label :for="'id_instruction_' + step.id">{{ $t("Instructions") }}</label>
|
||||
<mavon-editor v-model="step.instruction" :autofocus="false"
|
||||
style="height: 40vh; z-index: auto" :id="'id_instruction_' + step.id"
|
||||
style="z-index: auto" :id="'id_instruction_' + step.id"
|
||||
:language="'en'"
|
||||
:toolbars="md_editor_toolbars"/>
|
||||
:toolbars="md_editor_toolbars" :defaultOpen="'edit'"/>
|
||||
|
||||
<!-- TODO markdown DOCS link and markdown editor -->
|
||||
</div>
|
||||
@ -723,6 +744,7 @@ import GenericModalForm from "@/components/Modals/GenericModalForm"
|
||||
import mavonEditor from 'mavon-editor'
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
import _debounce from "lodash/debounce";
|
||||
import GenericMultiselect from "@/components/GenericMultiselect";
|
||||
// use
|
||||
Vue.use(mavonEditor)
|
||||
|
||||
@ -731,7 +753,7 @@ Vue.use(BootstrapVue)
|
||||
export default {
|
||||
name: "RecipeEditView",
|
||||
mixins: [ResolveUrlMixin, ApiMixin],
|
||||
components: {Multiselect, LoadingSpinner, draggable, GenericModalForm},
|
||||
components: {Multiselect, LoadingSpinner, draggable, GenericModalForm, GenericMultiselect},
|
||||
data() {
|
||||
return {
|
||||
recipe_id: window.RECIPE_ID,
|
||||
@ -771,9 +793,9 @@ export default {
|
||||
imagelink: false,
|
||||
code: true,
|
||||
table: false,
|
||||
fullscreen: true,
|
||||
readmodel: true,
|
||||
htmlcode: true,
|
||||
fullscreen: false,
|
||||
readmodel: false,
|
||||
htmlcode: false,
|
||||
help: true,
|
||||
undo: true,
|
||||
redo: true,
|
||||
|
@ -269,10 +269,6 @@ export default {
|
||||
},
|
||||
loadRecipe: function (recipe_id) {
|
||||
apiLoadRecipe(recipe_id).then((recipe) => {
|
||||
if (window.USER_SERVINGS !== 0) {
|
||||
recipe.servings = window.USER_SERVINGS
|
||||
}
|
||||
|
||||
let total_time = 0
|
||||
for (let step of recipe.steps) {
|
||||
for (let ingredient of step.ingredients) {
|
||||
|
119
vue/src/apps/SettingsView/SettingsView.vue
Normal file
119
vue/src/apps/SettingsView/SettingsView.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<template>
|
||||
|
||||
|
||||
<div id="app">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a :href="resolveDjangoUrl('view_settings')">{{
|
||||
$t('Settings')
|
||||
}}</a></li>
|
||||
<li class="breadcrumb-item" v-if="visible_settings === 'cosmetic'"
|
||||
@click="visible_settings = 'cosmetic'">{{ $t('Cosmetic') }}
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-if="visible_settings === 'account'"
|
||||
@click="visible_settings = 'account'"> {{ $t('Account') }}
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-if="visible_settings === 'search'"
|
||||
@click="visible_settings = 'search'">{{ $t('Search') }}
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-if="visible_settings === 'shopping'"
|
||||
@click="visible_settings = 'shopping'">{{ $t('Shopping_list') }}
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-if="visible_settings === 'meal_plan'"
|
||||
@click="visible_settings = 'meal_plan'">
|
||||
{{ $t('Meal_Plan') }}
|
||||
</li>
|
||||
<li class="breadcrumb-item" v-if="visible_settings === 'api'" @click="visible_settings = 'api'">
|
||||
{{ $t('API') }}
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-12">
|
||||
<b-nav vertical>
|
||||
<b-nav-item :active="visible_settings === 'cosmetic'" @click="visible_settings = 'cosmetic'"><i
|
||||
class="fas fa-fw fa-eye"></i> {{ $t('Cosmetic') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :active="visible_settings === 'account'" @click="visible_settings = 'account'"><i
|
||||
class="fas fa-fw fa-user"></i> {{ $t('Account') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :active="visible_settings === 'search'" @click="visible_settings = 'search'"><i
|
||||
class="fas fa-fw fa-search"></i> {{ $t('Search') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :active="visible_settings === 'shopping'" @click="visible_settings = 'shopping'"><i
|
||||
class="fas fa-fw fa-shopping-cart"></i> {{ $t('Shopping_list') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :active="visible_settings === 'meal_plan'" @click="visible_settings = 'meal_plan'"><i
|
||||
class="fas fa-fw fa-calendar"></i> {{ $t('Meal_Plan') }}
|
||||
</b-nav-item>
|
||||
<b-nav-item :active="visible_settings === 'api'" @click="visible_settings = 'api'"><i
|
||||
class="fas fa-fw fa-code"></i> {{ $t('API') }}
|
||||
</b-nav-item>
|
||||
</b-nav>
|
||||
</div>
|
||||
<div class="col-md-9 col-12">
|
||||
<cosmetic-settings-component v-if="visible_settings === 'cosmetic'"
|
||||
:user_id="user_id"></cosmetic-settings-component>
|
||||
<account-settings-component v-if="visible_settings === 'account'"
|
||||
:user_id="user_id"></account-settings-component>
|
||||
<search-settings-component v-if="visible_settings === 'search'"
|
||||
:user_id="user_id"></search-settings-component>
|
||||
<shopping-settings-component v-if="visible_settings === 'shopping'"
|
||||
:user_id="user_id"></shopping-settings-component>
|
||||
<meal-plan-settings-component v-if="visible_settings === 'meal_plan'"
|
||||
:user_id="user_id"></meal-plan-settings-component>
|
||||
<a-p-i-settings-component v-if="visible_settings === 'api'"
|
||||
:user_id="user_id"></a-p-i-settings-component>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue"
|
||||
import {BootstrapVue} from "bootstrap-vue"
|
||||
|
||||
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||
import CosmeticSettingsComponent from "@/components/Settings/CosmeticSettingsComponent";
|
||||
import AccountSettingsComponent from "@/components/Settings/AccountSettingsComponent";
|
||||
import SearchSettingsComponent from "@/components/Settings/SearchSettingsComponent";
|
||||
import ShoppingSettingsComponent from "@/components/Settings/ShoppingSettingsComponent";
|
||||
import MealPlanSettingsComponent from "@/components/Settings/MealPlanSettingsComponent";
|
||||
import APISettingsComponent from "@/components/Settings/APISettingsComponent";
|
||||
import {ResolveUrlMixin} from "@/utils/utils";
|
||||
|
||||
Vue.use(BootstrapVue)
|
||||
|
||||
export default {
|
||||
name: "ProfileView",
|
||||
mixins: [ResolveUrlMixin],
|
||||
components: {
|
||||
CosmeticSettingsComponent,
|
||||
AccountSettingsComponent,
|
||||
SearchSettingsComponent,
|
||||
ShoppingSettingsComponent,
|
||||
MealPlanSettingsComponent,
|
||||
APISettingsComponent
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible_settings: 'cosmetic',
|
||||
user_id: window.USER_ID,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
17
vue/src/apps/SettingsView/main.js
Normal file
17
vue/src/apps/SettingsView/main.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Vue from 'vue'
|
||||
import App from './SettingsView.vue'
|
||||
import i18n from '@/i18n'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
// TODO move this and other default stuff to centralized JS file (verify nothing breaks)
|
||||
let publicPath = localStorage.STATIC_URL + 'vue/'
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
publicPath = 'http://localhost:8080/'
|
||||
}
|
||||
export default __webpack_public_path__ = publicPath // eslint-disable-line
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
@ -33,7 +33,8 @@
|
||||
<template #title>
|
||||
<b-spinner v-if="loading" type="border" small class="d-inline-block"></b-spinner>
|
||||
<i v-if="!loading" class="fas fa-shopping-cart fa-fw d-inline-block d-md-none"></i>
|
||||
<span class="d-none d-md-inline-block">{{ $t('Shopping_list') }}</span>
|
||||
<span
|
||||
class="d-none d-md-inline-block">{{ $t('Shopping_list') + ` (${items.filter(x => x.checked === false).length})` }}</span>
|
||||
</template>
|
||||
<div class="container p-0 p-md-3" id="shoppinglist">
|
||||
<div class="row">
|
||||
@ -177,7 +178,7 @@
|
||||
<b-tab :title="$t('Recipes')">
|
||||
<template #title>
|
||||
<i class="fas fa-book fa-fw d-block d-md-none"></i>
|
||||
<span class="d-none d-md-block">{{ $t('Recipes') }}</span>
|
||||
<span class="d-none d-md-block">{{ $t('Recipes') + ` (${Recipes.length})` }}</span>
|
||||
</template>
|
||||
<div class="container p-0">
|
||||
<div class="row">
|
||||
@ -234,7 +235,9 @@
|
||||
</thead>
|
||||
<tr v-for="r in Recipes" :key="r.list_recipe">
|
||||
<td>{{ r.recipe_mealplan.name }}</td>
|
||||
<td><a :href="resolveDjangoUrl('view_recipe', r.recipe_mealplan.recipe)">{{ r.recipe_mealplan.recipe_name }}</a></td>
|
||||
<td><a :href="resolveDjangoUrl('view_recipe', r.recipe_mealplan.recipe)">{{
|
||||
r.recipe_mealplan.recipe_name
|
||||
}}</a></td>
|
||||
<td class="block-inline">
|
||||
<b-form-input min="1" type="number" :debounce="300"
|
||||
:value="r.recipe_mealplan.servings"
|
||||
@ -258,7 +261,7 @@
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<i class="fas fa-store-alt fa-fw d-block d-md-none"></i>
|
||||
<span class="d-none d-md-block">{{ $t('Supermarkets') }}</span>
|
||||
<span class="d-none d-md-block">{{ $t('Supermarkets') + ` (${supermarkets.length})` }}</span>
|
||||
</template>
|
||||
<div class="container p-0">
|
||||
<div class="row">
|
||||
@ -460,183 +463,7 @@
|
||||
</template>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-8">
|
||||
<b-card class="no-body">
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("mealplan_autoadd_shopping") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="checkbox" class="form-control settings-checkbox"
|
||||
v-model="settings.mealplan_autoadd_shopping" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">{{ $t("mealplan_autoadd_shopping_desc") }}</em>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="settings.mealplan_autoadd_shopping">
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("mealplan_autoexclude_onhand") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="checkbox" class="form-control settings-checkbox"
|
||||
v-model="settings.mealplan_autoexclude_onhand" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">{{ $t("mealplan_autoexclude_onhand_desc") }}</em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="settings.mealplan_autoadd_shopping">
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("mealplan_autoinclude_related") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="checkbox" class="form-control settings-checkbox"
|
||||
v-model="settings.mealplan_autoinclude_related" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("mealplan_autoinclude_related_desc") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("shopping_share") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<generic-multiselect
|
||||
size="sm"
|
||||
@change="
|
||||
settings.shopping_share = $event.val
|
||||
saveSettings()
|
||||
"
|
||||
:model="Models.USER"
|
||||
:initial_selection="settings.shopping_share"
|
||||
label="username"
|
||||
:multiple="true"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
:placeholder="$t('User')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">{{ $t("shopping_share_desc") }}</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("shopping_auto_sync") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="number" class="form-control" v-model="settings.shopping_auto_sync"
|
||||
@change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("shopping_auto_sync_desc") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("shopping_add_onhand") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="checkbox" class="form-control settings-checkbox"
|
||||
v-model="settings.shopping_add_onhand" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("shopping_add_onhand_desc") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("shopping_recent_days") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="number" class="form-control" v-model="settings.shopping_recent_days"
|
||||
@change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("shopping_recent_days_desc") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("filter_to_supermarket") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="checkbox" class="form-control settings-checkbox"
|
||||
v-model="settings.filter_to_supermarket" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("filter_to_supermarket_desc") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("default_delay") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input type="number" class="form-control" min="1" v-model="settings.default_delay"
|
||||
@change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("default_delay_desc") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("csv_delim_label") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input class="form-control" v-model="settings.csv_delim" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("csv_delim_help") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("csv_prefix_label") }}</div>
|
||||
<div class="col col-md-6 text-right">
|
||||
<input class="form-control" v-model="settings.csv_prefix" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("csv_prefix_help") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">{{ $t("left_handed") }}</div>
|
||||
<div class="col col-md-6">
|
||||
<input type="checkbox" class="form-control settings-checkbox"
|
||||
v-model="settings.left_handed" @change="saveSettings"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row sm mb-3">
|
||||
<div class="col">
|
||||
<em class="small text-muted">
|
||||
{{ $t("left_handed_help") }}
|
||||
</em>
|
||||
</div>
|
||||
</div>
|
||||
</b-card>
|
||||
<shopping-settings-component @updated="settings = $event" :user_id="user_id"></shopping-settings-component>
|
||||
</div>
|
||||
</div>
|
||||
</b-tab>
|
||||
@ -783,6 +610,7 @@ import ShoppingModal from "@/components/Modals/ShoppingModal"
|
||||
|
||||
import {ApiMixin, getUserPreference, StandardToasts, makeToast, ResolveUrlMixin} from "@/utils/utils"
|
||||
import {ApiApiFactory} from "@/utils/openapi/api"
|
||||
import ShoppingSettingsComponent from "@/components/Settings/ShoppingSettingsComponent";
|
||||
|
||||
Vue.use(BootstrapVue)
|
||||
Vue.use(VueCookies)
|
||||
@ -790,7 +618,7 @@ let SETTINGS_COOKIE_NAME = "shopping_settings"
|
||||
|
||||
export default {
|
||||
name: "ShoppingListView",
|
||||
mixins: [ApiMixin,ResolveUrlMixin],
|
||||
mixins: [ApiMixin, ResolveUrlMixin],
|
||||
components: {
|
||||
ContextMenu,
|
||||
ContextMenuItem,
|
||||
@ -801,7 +629,8 @@ export default {
|
||||
DownloadCSV,
|
||||
CopyToClipboard,
|
||||
ShoppingModal,
|
||||
draggable
|
||||
draggable,
|
||||
ShoppingSettingsComponent
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -837,6 +666,7 @@ export default {
|
||||
shopping_add_onhand: true,
|
||||
left_handed: false,
|
||||
},
|
||||
user_id: parseInt(localStorage.getItem('USER_ID')),
|
||||
editing_supermarket_categories: [],
|
||||
editing_supermarket: null,
|
||||
new_supermarket: {entrymode: false, value: undefined, editmode: undefined},
|
||||
@ -868,7 +698,7 @@ export default {
|
||||
case "category":
|
||||
return item?.food?.supermarket_category?.name ?? x
|
||||
case "created_by":
|
||||
return item?.created_by?.username ?? x
|
||||
return item?.created_by?.display_name ?? x
|
||||
case "recipe":
|
||||
return item?.recipe_mealplan?.recipe_name ?? x
|
||||
}
|
||||
@ -1315,16 +1145,6 @@ export default {
|
||||
|
||||
this.$refs.menu.open(e, value)
|
||||
},
|
||||
saveSettings: function () {
|
||||
let api = ApiApiFactory()
|
||||
api.partialUpdateUserPreference(this.settings.user, this.settings)
|
||||
.then((result) => {
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE)
|
||||
})
|
||||
.catch((err) => {
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
|
||||
})
|
||||
},
|
||||
saveThis: function (thisItem, toast = true) {
|
||||
let api = new ApiApiFactory()
|
||||
if (!thisItem?.id) {
|
||||
|
@ -141,6 +141,13 @@
|
||||
<label>{{ $t('Message') }}</label>
|
||||
<b-form-textarea v-model="space.message"></b-form-textarea>
|
||||
|
||||
<label>{{ $t('Image') }}</label>
|
||||
<generic-multiselect :initial_single_selection="space.image"
|
||||
:model="Models.USERFILE"
|
||||
:multiple="false"
|
||||
@change="space.image = $event.val;"></generic-multiselect>
|
||||
<br/>
|
||||
|
||||
<b-form-checkbox v-model="space.show_facet_count"> Facet Count</b-form-checkbox>
|
||||
<span class="text-muted small">{{ $t('facet_count_info') }}</span><br/>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
{{ book_copy.icon }} {{ book_copy.name }}
|
||||
<span class="float-right text-primary" @click="editOrSave"><i class="fa" v-bind:class="{ 'fa-pen': !editing, 'fa-save': editing }" aria-hidden="true"></i></span>
|
||||
</h5>
|
||||
<b-badge class="font-weight-normal mr-1" v-for="u in book_copy.shared" v-bind:key="u.id" variant="primary" pill>{{ u.username }}</b-badge>
|
||||
<b-badge class="font-weight-normal mr-1" v-for="u in book_copy.shared" v-bind:key="u.id" variant="primary" pill>{{ u.display_name }}</b-badge>
|
||||
</b-card-header>
|
||||
<b-card-body class="p-4">
|
||||
<div class="form-group" v-if="editing">
|
||||
@ -25,7 +25,7 @@
|
||||
@change="book_copy.shared = $event.val"
|
||||
parent_variable="book.shared"
|
||||
:initial_selection="book.shared"
|
||||
:label="'username'"
|
||||
:label="'display_name'"
|
||||
:model="Models.USER_NAME"
|
||||
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
|
||||
v-bind:placeholder="$t('Share')"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user