mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
Merge branch 'develop' into feature/vue3
This commit is contained in:
@@ -35,6 +35,20 @@ def get_filetype(name):
|
||||
return '.jpeg'
|
||||
|
||||
|
||||
def is_file_type_allowed(filename, image_only=False):
|
||||
is_file_allowed = False
|
||||
allowed_file_types = ['.pdf','.docx', '.xlsx']
|
||||
allowed_image_types = ['.png', '.jpg', '.jpeg', '.gif']
|
||||
check_list = allowed_image_types
|
||||
if not image_only:
|
||||
check_list += allowed_file_types
|
||||
|
||||
for file_type in check_list:
|
||||
if filename.endswith(file_type):
|
||||
is_file_allowed = True
|
||||
|
||||
return is_file_allowed
|
||||
|
||||
# TODO this whole file needs proper documentation, refactoring, and testing
|
||||
# TODO also add env variable to define which images sizes should be compressed
|
||||
# filetype argument can not be optional, otherwise this function will treat all images as if they were a jpeg
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
|
||||
"PO-Revision-Date: 2024-11-22 07:58+0000\n"
|
||||
"Last-Translator: Oleh Hudyma <oleg.hudymaa@gmail.com>\n"
|
||||
"PO-Revision-Date: 2025-01-16 18:58+0000\n"
|
||||
"Last-Translator: Anton Shevtsov <ashevtsovs@gmail.com>\n"
|
||||
"Language-Team: Ukrainian <http://translate.tandoor.dev/projects/tandoor/"
|
||||
"recipes-backend/uk/>\n"
|
||||
"Language: uk\n"
|
||||
@@ -18,7 +18,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.6.2\n"
|
||||
"X-Generator: Weblate 5.8.4\n"
|
||||
|
||||
#: .\cookbook\forms.py:45
|
||||
msgid ""
|
||||
@@ -32,7 +32,7 @@ msgstr ""
|
||||
|
||||
#: .\cookbook\forms.py:62 .\cookbook\forms.py:246 .\cookbook\views\lists.py:103
|
||||
msgid "Keywords"
|
||||
msgstr ""
|
||||
msgstr "Ключові слова"
|
||||
|
||||
#: .\cookbook\forms.py:62
|
||||
msgid "Preparation time in minutes"
|
||||
@@ -941,13 +941,13 @@ msgstr ""
|
||||
#: .\cookbook\templates\ingredient_editor.html:7
|
||||
#: .\cookbook\templates\ingredient_editor.html:13
|
||||
msgid "Ingredient Editor"
|
||||
msgstr ""
|
||||
msgstr "Редактор Інгредієнтів"
|
||||
|
||||
#: .\cookbook\templates\base.html:275
|
||||
#: .\cookbook\templates\export_response.html:7
|
||||
#: .\cookbook\templates\test2.html:14 .\cookbook\templates\test2.html:20
|
||||
msgid "Export"
|
||||
msgstr ""
|
||||
msgstr "Експорт"
|
||||
|
||||
#: .\cookbook\templates\base.html:287
|
||||
msgid "Properties"
|
||||
|
||||
@@ -12,21 +12,25 @@ class Local(Provider):
|
||||
|
||||
@staticmethod
|
||||
def import_all(monitor):
|
||||
if '/etc/' in monitor.path or '/root/' in monitor.path or '/mediafiles/' in monitor.path or '/usr/' in monitor.path:
|
||||
return False
|
||||
|
||||
files = [f for f in listdir(monitor.path) if isfile(join(monitor.path, f))]
|
||||
|
||||
import_count = 0
|
||||
for file in files:
|
||||
path = monitor.path + '/' + file
|
||||
if not Recipe.objects.filter(file_path__iexact=path, space=monitor.space).exists() and not RecipeImport.objects.filter(file_path=path, space=monitor.space).exists():
|
||||
name = os.path.splitext(file)[0]
|
||||
new_recipe = RecipeImport(
|
||||
name=name,
|
||||
file_path=path,
|
||||
storage=monitor.storage,
|
||||
space=monitor.space,
|
||||
)
|
||||
new_recipe.save()
|
||||
import_count += 1
|
||||
if file.endswith('.pdf') or file.endswith('.png') or file.endswith('.jpg') or file.endswith('.jpeg') or file.endswith('.gif'):
|
||||
path = monitor.path + '/' + file
|
||||
if not Recipe.objects.filter(file_path__iexact=path, space=monitor.space).exists() and not RecipeImport.objects.filter(file_path=path, space=monitor.space).exists():
|
||||
name = os.path.splitext(file)[0]
|
||||
new_recipe = RecipeImport(
|
||||
name=name,
|
||||
file_path=path,
|
||||
storage=monitor.storage,
|
||||
space=monitor.space,
|
||||
)
|
||||
new_recipe.save()
|
||||
import_count += 1
|
||||
|
||||
log_entry = SyncLog(
|
||||
status='SUCCESS',
|
||||
|
||||
@@ -24,6 +24,7 @@ from rest_framework.fields import IntegerField
|
||||
|
||||
from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
|
||||
from cookbook.helper.HelperFunctions import str2bool
|
||||
from cookbook.helper.image_processing import is_file_type_allowed
|
||||
from cookbook.helper.permission_helper import above_space_limit
|
||||
from cookbook.helper.property_helper import FoodPropertyHelper
|
||||
from cookbook.helper.shopping_helper import RecipeShoppingEditor
|
||||
@@ -267,12 +268,17 @@ class UserFileSerializer(serializers.ModelSerializer):
|
||||
raise ValidationError(_('You have reached your file upload limit.'))
|
||||
|
||||
def create(self, validated_data):
|
||||
if not is_file_type_allowed(validated_data['file'].name):
|
||||
return None
|
||||
|
||||
self.check_file_limit(validated_data)
|
||||
validated_data['created_by'] = self.context['request'].user
|
||||
validated_data['space'] = self.context['request'].space
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if not is_file_type_allowed(validated_data['file'].name):
|
||||
return None
|
||||
self.check_file_limit(validated_data)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
@@ -1032,6 +1038,16 @@ class RecipeImageSerializer(WritableNestedModelSerializer):
|
||||
image = serializers.ImageField(required=False, allow_null=True)
|
||||
image_url = serializers.CharField(max_length=4096, required=False, allow_null=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
if not is_file_type_allowed(validated_data['image'].name, image_only=True):
|
||||
return None
|
||||
return super().create( validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if not is_file_type_allowed(validated_data['image'].name, image_only=True):
|
||||
return None
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
class Meta:
|
||||
model = Recipe
|
||||
fields = ['image', 'image_url', ]
|
||||
|
||||
@@ -31,12 +31,12 @@ def test_edit_storage(storage_obj, a1_s1, a1_s2):
|
||||
}
|
||||
)
|
||||
storage_obj.refresh_from_db()
|
||||
assert r.status_code == 200
|
||||
r_messages = [m for m in get_messages(r.wsgi_request)]
|
||||
assert not any(m.level > messages.SUCCESS for m in r_messages)
|
||||
assert r.status_code == 302
|
||||
#r_messages = [m for m in get_messages(r.wsgi_request)]
|
||||
#assert not any(m.level > messages.SUCCESS for m in r_messages)
|
||||
|
||||
assert storage_obj.password == '1234_pw'
|
||||
assert storage_obj.token == '1234_token'
|
||||
#assert storage_obj.password == '1234_pw'
|
||||
#assert storage_obj.token == '1234_token'
|
||||
|
||||
r = a1_s2.post(
|
||||
reverse('edit_storage', args={storage_obj.pk}),
|
||||
@@ -54,7 +54,7 @@ def test_edit_storage(storage_obj, a1_s1, a1_s2):
|
||||
['a_u', 302],
|
||||
['g1_s1', 302],
|
||||
['u1_s1', 302],
|
||||
['a1_s1', 200],
|
||||
['a1_s1', 302],
|
||||
['g1_s2', 302],
|
||||
['u1_s2', 302],
|
||||
['a1_s2', 404],
|
||||
|
||||
@@ -80,7 +80,7 @@ class SyncUpdate(GroupRequiredMixin, UpdateView, SpaceFormMixing):
|
||||
def edit_storage(request, pk):
|
||||
instance: Storage = get_object_or_404(Storage, pk=pk, space=request.space)
|
||||
|
||||
if not (instance.created_by == request.user or request.user.is_superuser):
|
||||
if not request.user.is_superuser:
|
||||
messages.add_message(request, messages.ERROR, _('You cannot edit this storage!'))
|
||||
return HttpResponseRedirect(reverse('list_storage'))
|
||||
|
||||
|
||||
@@ -58,10 +58,16 @@ class StorageCreate(GroupRequiredMixin, CreateView):
|
||||
obj = form.save(commit=False)
|
||||
obj.created_by = self.request.user
|
||||
obj.space = self.request.space
|
||||
obj.save()
|
||||
|
||||
if self.request.space.demo or settings.HOSTED:
|
||||
messages.add_message(self.request, messages.ERROR, _('This feature is not yet available in the hosted version of tandoor!'))
|
||||
return redirect('index')
|
||||
|
||||
if not self.request.user.is_superuser:
|
||||
messages.add_message(self.request, messages.ERROR, _('This feature is only available for the instance administrator (superuser)'))
|
||||
return redirect('index')
|
||||
|
||||
obj.save()
|
||||
return HttpResponseRedirect(reverse('edit_storage', kwargs={'pk': obj.pk}))
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
Reference in New Issue
Block a user