added ability to delete external recipe file

This commit is contained in:
vabene1111
2025-09-04 21:09:34 +02:00
parent 1618f8df79
commit 8550387e0c
3 changed files with 137 additions and 4 deletions

View File

@@ -1449,6 +1449,22 @@ class RecipeViewSet(LoggingMixin, viewsets.ModelViewSet):
return Response(serializer.errors, 400)
@extend_schema(responses=RecipeSerializer(many=False))
@decorators.action(detail=True, pagination_class=None, methods=['PATCH'], serializer_class=RecipeSerializer)
def delete_external(self, request, pk):
obj = self.get_object()
if obj.get_space() != request.space and has_group_permission(request.user, ['user']):
raise PermissionDenied(detail='You do not have the required permission to perform this action', code=403)
if obj.storage:
get_recipe_provider(obj).delete_file(obj)
obj.storage = None
obj.file_path = ''
obj.file_uid = ''
obj.save()
return Response(self.serializer_class(obj, many=False, context={'request': request}).data)
@extend_schema_view(list=extend_schema(
parameters=[OpenApiParameter(name='food_id', description='ID of food to filter for', type=int),

View File

@@ -83,8 +83,10 @@
<v-icon icon="fa-solid fa-arrow-down-1-9"></v-icon>
</v-btn>
<v-btn prepend-icon="fa-solid fa-maximize" @click="handleSplitAllSteps" :disabled="editingObj.steps.length < 1"><span v-if="!mobile">{{ $t('Split') }}</span></v-btn>
<v-btn prepend-icon="fa-solid fa-minimize" @click="handleMergeAllSteps" :disabled="editingObj.steps.length < 2"><span v-if="!mobile">{{ $t('Merge') }}</span></v-btn>
<v-btn prepend-icon="fa-solid fa-maximize" @click="handleSplitAllSteps" :disabled="editingObj.steps.length < 1"><span
v-if="!mobile">{{ $t('Split') }}</span></v-btn>
<v-btn prepend-icon="fa-solid fa-minimize" @click="handleMergeAllSteps" :disabled="editingObj.steps.length < 2"><span
v-if="!mobile">{{ $t('Merge') }}</span></v-btn>
</v-btn-group>
@@ -109,6 +111,15 @@
<model-select mode="tags" model="User" :label="$t('Share')" persistent-hint v-model="editingObj.shared"
append-to-body v-if="editingObj._private"></model-select>
<div class="mt-2" v-if="editingObj.filePath">
{{ $t('ExternalRecipe') }}
<v-text-field readonly v-model="editingObj.filePath"></v-text-field>
<v-btn prepend-icon="$delete" color="error" :loading="loading">{{ $t('delete_title', {type: $t('ExternalRecipe')}) }}
<delete-confirm-dialog :object-name="editingObj.filePath" :model-name="$t('ExternalRecipe')" @delete="deleteExternalFile()"></delete-confirm-dialog>
</v-btn>
</div>
</v-form>
</v-tabs-window-item>
</v-tabs-window>
@@ -143,7 +154,7 @@
<script setup lang="ts">
import {onMounted, PropType, ref, shallowRef, watch} from "vue";
import {Ingredient, Recipe, Step} from "@/openapi";
import {ApiApi, Ingredient, Recipe, Step} from "@/openapi";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
@@ -156,8 +167,9 @@ import ClosableHelpAlert from "@/components/display/ClosableHelpAlert.vue";
import {useDisplay} from "vuetify";
import {isSpaceAtRecipeLimit} from "@/utils/logic_utils";
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import SpaceSettings from "@/components/settings/SpaceSettings.vue";
import {mergeAllSteps, splitAllSteps} from "@/utils/step_utils.ts";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore.ts";
const props = defineProps({
@@ -267,6 +279,21 @@ function handleSplitAllSteps(): void {
}
}
/**
* deletes the external file for the recipe
*/
function deleteExternalFile() {
let api = new ApiApi()
loading.value = true
api.apiRecipeDeleteExternalPartialUpdate({id: editingObj.value.id!, patchedRecipe: editingObj.value}).then(r => {
editingObj.value = r
}).catch(err => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
}).finally(() => {
loading.value = false
})
}
</script>
<style scoped>

View File

@@ -759,6 +759,11 @@ export interface ApiEnterpriseSocialRecipeCreateRequest {
recipe: Omit<Recipe, 'image'|'createdBy'|'createdAt'|'updatedAt'|'foodProperties'|'rating'|'lastCooked'>;
}
export interface ApiEnterpriseSocialRecipeDeleteExternalPartialUpdateRequest {
id: number;
patchedRecipe?: Omit<PatchedRecipe, 'image'|'createdBy'|'createdAt'|'updatedAt'|'foodProperties'|'rating'|'lastCooked'>;
}
export interface ApiEnterpriseSocialRecipeDestroyRequest {
id: number;
}
@@ -1512,6 +1517,11 @@ export interface ApiRecipeCreateRequest {
recipe: Omit<Recipe, 'image'|'createdBy'|'createdAt'|'updatedAt'|'foodProperties'|'rating'|'lastCooked'>;
}
export interface ApiRecipeDeleteExternalPartialUpdateRequest {
id: number;
patchedRecipe?: Omit<PatchedRecipe, 'image'|'createdBy'|'createdAt'|'updatedAt'|'foodProperties'|'rating'|'lastCooked'>;
}
export interface ApiRecipeDestroyRequest {
id: number;
}
@@ -4411,6 +4421,46 @@ export class ApiApi extends runtime.BaseAPI {
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiEnterpriseSocialRecipeDeleteExternalPartialUpdateRaw(requestParameters: ApiEnterpriseSocialRecipeDeleteExternalPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Recipe>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiEnterpriseSocialRecipeDeleteExternalPartialUpdate().'
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters['Content-Type'] = 'application/json';
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/enterprise-social-recipe/{id}/delete_external/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'PATCH',
headers: headerParameters,
query: queryParameters,
body: PatchedRecipeToJSON(requestParameters['patchedRecipe']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiEnterpriseSocialRecipeDeleteExternalPartialUpdate(requestParameters: ApiEnterpriseSocialRecipeDeleteExternalPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Recipe> {
const response = await this.apiEnterpriseSocialRecipeDeleteExternalPartialUpdateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
@@ -10819,6 +10869,46 @@ export class ApiApi extends runtime.BaseAPI {
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeDeleteExternalPartialUpdateRaw(requestParameters: ApiRecipeDeleteExternalPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Recipe>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiRecipeDeleteExternalPartialUpdate().'
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters['Content-Type'] = 'application/json';
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/recipe/{id}/delete_external/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'PATCH',
headers: headerParameters,
query: queryParameters,
body: PatchedRecipeToJSON(requestParameters['patchedRecipe']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeDeleteExternalPartialUpdate(requestParameters: ApiRecipeDeleteExternalPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Recipe> {
const response = await this.apiRecipeDeleteExternalPartialUpdateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/