new upload options

This commit is contained in:
hay-kot 2021-04-11 13:09:15 -08:00
commit 376b10a52c
6 changed files with 133 additions and 25 deletions

View file

@ -0,0 +1,76 @@
<template>
<div class="text-center">
<v-menu offset-y top nudge-top="6" :close-on-content-click="false">
<template v-slot:activator="{ on, attrs }">
<v-btn color="accent" dark v-bind="attrs" v-on="on">
Image
</v-btn>
</template>
<v-card width="400">
<v-card-title class="headline flex mb-0">
<div>
Recipe Image
</div>
<UploadBtn
class="ml-auto"
url="none"
file-name="image"
:text-btn="false"
@uploaded="uploadImage"
/>
</v-card-title>
<v-card-text class="mt-n5">
<div>
<v-text-field label="URL" class="pt-5" clearable v-model="url">
<template v-slot:append-outer>
<v-btn
class="ml-2"
color="primary"
@click="getImageFromURL"
:loading="loading"
>
Get
</v-btn>
</template>
</v-text-field>
</div>
</v-card-text>
</v-card>
</v-menu>
</div>
</template>
<script>
const REFRESH_EVENT = "refresh";
const UPLOAD_EVENT = "upload";
import UploadBtn from "@/components/UI/UploadBtn";
import { api } from "@/api";
// import axios from "axios";
export default {
components: {
UploadBtn,
},
props: {
slug: String,
},
data: () => ({
items: [{ title: "Upload Image" }, { title: "From URL" }],
url: "",
loading: false,
}),
methods: {
uploadImage(fileObject) {
this.$emit(UPLOAD_EVENT, fileObject);
},
async getImageFromURL() {
this.loading = true;
const response = await api.recipes.updateImagebyURL(this.slug, this.url);
if (response) this.$emit(REFRESH_EVENT);
this.loading = false;
},
},
};
</script>
<style lang="scss" scoped>
</style>

View file

@ -2,16 +2,12 @@
<v-form ref="form"> <v-form ref="form">
<v-card-text> <v-card-text>
<v-row dense> <v-row dense>
<v-col cols="3"></v-col> <ImageUploadBtn
<v-col> class="mt-2"
<v-file-input @upload="uploadImage"
v-model="fileObject" :slug="value.slug"
:label="$t('general.image-file')" @refresh="$emit('upload')"
truncate-length="30" />
@change="uploadImage"
></v-file-input>
</v-col>
<v-col cols="3"></v-col>
</v-row> </v-row>
<v-row dense> <v-row dense>
<v-col> <v-col>
@ -223,12 +219,12 @@
<script> <script>
import draggable from "vuedraggable"; import draggable from "vuedraggable";
import { api } from "@/api";
import utils from "@/utils"; import utils from "@/utils";
import BulkAdd from "./BulkAdd"; import BulkAdd from "./BulkAdd";
import ExtrasEditor from "./ExtrasEditor"; import ExtrasEditor from "./ExtrasEditor";
import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector"; import CategoryTagSelector from "@/components/FormHelpers/CategoryTagSelector";
import NutritionEditor from "./NutritionEditor"; import NutritionEditor from "./NutritionEditor";
import ImageUploadBtn from "./ImageUploadBtn.vue";
export default { export default {
components: { components: {
BulkAdd, BulkAdd,
@ -236,6 +232,7 @@ export default {
draggable, draggable,
CategoryTagSelector, CategoryTagSelector,
NutritionEditor, NutritionEditor,
ImageUploadBtn,
}, },
props: { props: {
value: Object, value: Object,
@ -254,12 +251,8 @@ export default {
}; };
}, },
methods: { methods: {
uploadImage() { uploadImage(fileObject) {
this.$emit("upload", this.fileObject); this.$emit("upload", fileObject);
},
async updateImage() {
const slug = this.value.slug;
api.recipes.updateImage(slug, this.fileObject);
}, },
toggleDisabled(stepIndex) { toggleDisabled(stepIndex) {
if (this.disabledSteps.includes(stepIndex)) { if (this.disabledSteps.includes(stepIndex)) {

View file

@ -1,7 +1,12 @@
<template> <template>
<v-form ref="file"> <v-form ref="file">
<input ref="uploader" class="d-none" type="file" @change="onFileChanged" /> <input ref="uploader" class="d-none" type="file" @change="onFileChanged" />
<v-btn :loading="isSelecting" @click="onButtonClick" color="accent" text> <v-btn
:loading="isSelecting"
@click="onButtonClick"
color="accent"
:text="textBtn"
>
<v-icon left> {{ icon }}</v-icon> <v-icon left> {{ icon }}</v-icon>
{{ text ? text : defaultText }} {{ text ? text : defaultText }}
</v-btn> </v-btn>
@ -13,10 +18,17 @@ const UPLOAD_EVENT = "uploaded";
import { api } from "@/api"; import { api } from "@/api";
export default { export default {
props: { props: {
post: {
type: Boolean,
default: true,
},
url: String, url: String,
text: { default: "Upload" }, text: { default: "Upload" },
icon: { default: "mdi-cloud-upload" }, icon: { default: "mdi-cloud-upload" },
fileName: { default: "archive" }, fileName: { default: "archive" },
textBtn: {
default: true,
},
}, },
data: () => ({ data: () => ({
file: null, file: null,
@ -33,6 +45,12 @@ export default {
async upload() { async upload() {
if (this.file != null) { if (this.file != null) {
this.isSelecting = true; this.isSelecting = true;
if (this.post) {
this.$emit(UPLOAD_EVENT, this.file);
this.isSelecting = false;
return;
}
let formData = new FormData(); let formData = new FormData();
formData.append(this.fileName, this.file); formData.append(this.fileName, this.file);

View file

@ -152,6 +152,7 @@ export default {
methods: { methods: {
getImageFile(fileObject) { getImageFile(fileObject) {
this.fileObject = fileObject; this.fileObject = fileObject;
this.saveImage();
}, },
async getRecipeDetails() { async getRecipeDetails() {
this.recipeDetails = await api.recipes.requestDetails(this.currentRecipe); this.recipeDetails = await api.recipes.requestDetails(this.currentRecipe);
@ -173,19 +174,21 @@ export default {
return this.$refs.recipeEditor.validateRecipe(); return this.$refs.recipeEditor.validateRecipe();
} }
}, },
async saveImage() {
if (this.fileObject) {
await api.recipes.updateImage(this.recipeDetails.slug, this.fileObject);
}
this.imageKey += 1;
},
async saveRecipe() { async saveRecipe() {
if (this.validateRecipe()) { if (this.validateRecipe()) {
let slug = await api.recipes.update(this.recipeDetails); let slug = await api.recipes.update(this.recipeDetails);
if (this.fileObject) { if (this.fileObject) {
await api.recipes.updateImage( this.saveImage();
this.recipeDetails.slug,
this.fileObject
);
} }
this.form = false; this.form = false;
this.imageKey += 1;
if (slug != this.recipeDetails.slug) { if (slug != this.recipeDetails.slug) {
this.$router.push(`/recipe/${slug}`); this.$router.push(`/recipe/${slug}`);
} }

View file

@ -1,5 +1,7 @@
import shutil
from enum import Enum from enum import Enum
import requests
from fastapi import APIRouter, Depends, File, Form, HTTPException from fastapi import APIRouter, Depends, File, Form, HTTPException
from fastapi.responses import FileResponse from fastapi.responses import FileResponse
from mealie.db.database import db from mealie.db.database import db
@ -7,7 +9,7 @@ from mealie.db.db_setup import generate_session
from mealie.routes.deps import get_current_user from mealie.routes.deps import get_current_user
from mealie.schema.recipe import Recipe, RecipeURLIn from mealie.schema.recipe import Recipe, RecipeURLIn
from mealie.schema.snackbar import SnackResponse from mealie.schema.snackbar import SnackResponse
from mealie.services.image.image import IMG_OPTIONS, delete_image, read_image, rename_image, write_image from mealie.services.image.image import IMG_OPTIONS, delete_image, read_image, rename_image, scrape_image, write_image
from mealie.services.scraper.scraper import create_from_url from mealie.services.scraper.scraper import create_from_url
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
@ -120,3 +122,16 @@ def update_recipe_image(
db.recipes.update_image(session, recipe_slug, extension) db.recipes.update_image(session, recipe_slug, extension)
return response return response
@router.post("/{recipe_slug}/image")
def scrape_image_url(
recipe_slug: str,
url: RecipeURLIn,
current_user=Depends(get_current_user),
):
""" Removes an existing image and replaces it with the incoming file. """
scrape_image(url.url, recipe_slug)
return SnackResponse.success("Recipe Image Updated")

View file

@ -64,6 +64,9 @@ def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path:
if isinstance(file_data, Path): if isinstance(file_data, Path):
shutil.copy2(file_data, image_path) shutil.copy2(file_data, image_path)
elif isinstance(file_data, bytes):
with open(image_path, "ab") as f:
f.write(file_data)
else: else:
with open(image_path, "ab") as f: with open(image_path, "ab") as f:
shutil.copyfileobj(file_data, f) shutil.copyfileobj(file_data, f)
@ -106,7 +109,7 @@ def scrape_image(image_url: str, slug: str) -> Path:
write_image(slug, r.raw, filename.suffix) write_image(slug, r.raw, filename.suffix)
filename.unlink() filename.unlink(missing_ok=True)
return slug return slug