From 6baf640e6da800c4b50e1ad5e7b5cfb2213963a8 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Sun, 22 Jun 2025 10:03:34 +0200 Subject: [PATCH] fixed file upload --- cookbook/helper/image_processing.py | 2 +- cookbook/serializer.py | 19 ++++++++++++------- .../model_editors/UserFileEditor.vue | 9 +++++++++ vue3/src/composables/useFileApi.ts | 16 ++++++++++------ vue3/src/pages/ModelListPage.vue | 15 +++++++++------ 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/cookbook/helper/image_processing.py b/cookbook/helper/image_processing.py index c252e24ff..70125a33d 100644 --- a/cookbook/helper/image_processing.py +++ b/cookbook/helper/image_processing.py @@ -37,7 +37,7 @@ def get_filetype(name): def is_file_type_allowed(filename, image_only=False): is_file_allowed = False - allowed_file_types = ['.pdf', '.docx', '.xlsx'] + allowed_file_types = ['.pdf', '.docx', '.xlsx', '.css'] allowed_image_types = ['.png', '.jpg', '.jpeg', '.gif', '.webp'] check_list = allowed_image_types if not image_only: diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 02e3de0e7..395fb2812 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -268,19 +268,24 @@ class UserFileSerializer(serializers.ModelSerializer): > self.context['request'].space.max_file_storage_mb != 0): 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 + def check_file_type(self, validated_data): + print('checking file type') + if 'file' in validated_data: + print('filke present in data') + if not is_file_type_allowed(validated_data['file'].name, image_only=False): + print('is not allowed') + raise ValidationError(_('The given file type is not allowed.')) + def create(self, validated_data): self.check_file_limit(validated_data) + self.check_file_type(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) + self.check_file_type(validated_data) return super().update(instance, validated_data) class Meta: @@ -456,7 +461,7 @@ class ConnectorConfigSerializer(SpacedModelSerializer): class Meta: model = ConnectorConfig fields = ( - 'id', 'name', 'type','url', 'token', 'todo_entity', 'enabled', + 'id', 'name', 'type', 'url', 'token', 'todo_entity', 'enabled', 'on_shopping_list_entry_created_enabled', 'on_shopping_list_entry_updated_enabled', 'on_shopping_list_entry_deleted_enabled', 'supports_description_field', 'created_by' ) @@ -481,7 +486,7 @@ class StorageSerializer(WritableNestedModelSerializer, SpacedModelSerializer): 'token', 'url', 'path', 'created_by' ) - read_only_fields = ( 'id', 'created_by',) + read_only_fields = ('id', 'created_by',) extra_kwargs = { 'password': {'write_only': True}, diff --git a/vue3/src/components/model_editors/UserFileEditor.vue b/vue3/src/components/model_editors/UserFileEditor.vue index 52b29ba55..3290c8d79 100644 --- a/vue3/src/components/model_editors/UserFileEditor.vue +++ b/vue3/src/components/model_editors/UserFileEditor.vue @@ -79,11 +79,20 @@ onMounted(() => { * save file to database via fileApi composable */ function saveFile() { + loading.value = true + + let event: ("create" | "save") = isUpdate() ? 'save' : 'create' + createOrUpdateUserFile(editingObj.value.name, file.value, editingObj.value.id).then(r => { editingObj.value = r + editingObjChanged.value = false + emit(event, r) useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS) }).catch(err => { useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err) + }).finally(() => { + editingObjChanged.value = false + loading.value = false }) } diff --git a/vue3/src/composables/useFileApi.ts b/vue3/src/composables/useFileApi.ts index 86a81429b..e5b269606 100644 --- a/vue3/src/composables/useFileApi.ts +++ b/vue3/src/composables/useFileApi.ts @@ -1,7 +1,7 @@ import {useDjangoUrls} from "@/composables/useDjangoUrls"; import {ref} from "vue"; import {getCookie} from "@/utils/cookie"; -import {RecipeFromSourceResponseFromJSON, RecipeImageFromJSON, UserFile, UserFileFromJSON} from "@/openapi"; +import {RecipeFromSourceResponseFromJSON, RecipeImageFromJSON, ResponseError, UserFile, UserFileFromJSON} from "@/openapi"; /** @@ -40,9 +40,13 @@ export function useFileApi() { headers: {'X-CSRFToken': getCookie('csrftoken')}, body: formData }).then(r => { - return r.json().then(r => { - return UserFileFromJSON(r) - }) + if (r.ok) { + return r.json().then(r => { + return UserFileFromJSON(r) + }) + } else { + throw new ResponseError(r) + } }).finally(() => { fileApiLoading.value = false }) @@ -81,10 +85,10 @@ export function useFileApi() { * @param file file object to upload * @param text text to import */ - function doAiImport(file: File|null, text: string = '') { + function doAiImport(file: File | null, text: string = '') { let formData = new FormData() - if(file != null){ + if (file != null) { formData.append('file', file) } else { formData.append('file', '') diff --git a/vue3/src/pages/ModelListPage.vue b/vue3/src/pages/ModelListPage.vue index 39323ae64..525272c09 100644 --- a/vue3/src/pages/ModelListPage.vue +++ b/vue3/src/pages/ModelListPage.vue @@ -21,7 +21,9 @@ + @create="loadItems({page: tablePage, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery})" + @save="loadItems({page: tablePage, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery})" + @delete="loadItems({page: tablePage, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery})"> @@ -51,7 +53,8 @@ - + {{ $t('Edit') }} @@ -71,7 +74,7 @@ {{ $t('Import') }} - + {{ $t('Import') }} @@ -209,8 +212,8 @@ function changeModel(m: Model) { * convert a RecipeImport to a "real" external recipes and reload the table * @param item */ -function importRecipe(item: RecipeImport){ -let api = new ApiApi() +function importRecipe(item: RecipeImport) { + let api = new ApiApi() api.apiRecipeImportImportRecipeCreate({id: item.id!, recipeImport: item}).then(r => { loadItems({page: 1, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery.value}) }).catch(err => { @@ -221,7 +224,7 @@ let api = new ApiApi() /** * convert all RecipeImports to "real" external recipes and reload the table (should be empty afterwards) */ -function importAllRecipes(){ +function importAllRecipes() { let api = new ApiApi() api.apiRecipeImportImportAllCreate({recipeImport: {} as RecipeImport}).then(r => {