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 => {