Ver código fonte

Implement imagen saving backend. Not working tho

Tatiana Inama 6 anos atrás
pai
commit
849ac0d8f9

+ 27 - 4
ktchn/src/recipes/controller.ts

@@ -6,6 +6,7 @@ import Scrape from './scrape/index';
 import { ScrapedRecipe } from './model';
 import Ingredient from '../ingredients/model';
 import { dissoc } from 'ramda';
+import fs from 'fs';
 
 function validRecipe(data: any): Promise<Recipe> {
   return new Promise(function(resolve, reject) {
@@ -18,6 +19,7 @@ type Controller = (db: IMongoService) => (req: Request, res: Response, next: Nex
 type ChainPController<T, U> = (req: Request, res: Response, next: NextFunction) => (result: T) => Promise<U>;
 
 const getSuggestions = (db: IMongoService) => async function(ingredient: IIngredient): Promise<IngredientSuggestion> {
+  // @ts-ignore: yes
   const suggestions = await db.find<Ingredient>({$text: {$search: ingredient.name}}, { score: { $meta: "textScore" } });
   return {
     ...ingredient,
@@ -42,11 +44,32 @@ const scrapeRecipe: (db: IMongoService) => ChainPController<void, ScrapedRecipe>
     })
 }
 
+const saveImage = async (recipe: Recipe) => {
+  if (recipe.image) {
+    try {
+      const [ prefix, base64Img ] = recipe.image.split(',');
+      const name = `${Date.now()}.${prefix.replace('data:image/', '').split(';', 1)}`;
+      fs.writeFileSync(`${__dirname}/public/${name}`, base64Img, { encoding: 'base64'});
+      return {
+        ...recipe,
+        image: name
+      }
+    } catch (e) {
+      throw Error(e);
+    }
+  } else {
+    return recipe;
+  }
+}
+
 const save: Controller = (db) => ({ body }, res) => {
-  return validRecipe(body).then(
-    recipe => db.insertOne(recipe).then(
-      dbRecipe => res.json(dbRecipe)
-  ));
+  return validRecipe(body)
+    //.then(saveImage)
+    .then(db.insertOne)
+    .then(dbrecipe => {
+      return dbrecipe
+    })
+    .then(res.json);
 };
 
 const get: Controller = (db) => ({ query }, res) => {

+ 1 - 0
ktchn/src/recipes/model.ts

@@ -59,6 +59,7 @@ export interface Recipe {
   tags?: string[];
   course?: string[];
   summary?: string;
+  image?: string;
 }
 
 export interface ScrapedRecipe extends Recipe {

+ 2 - 2
ktchn/src/server.ts

@@ -55,8 +55,8 @@ class App {
     this.app.set("port", process.env.PORT || 3000);
     this.app.use(logger("dev"));
     this.app.use(express.json());
-    this.app.use(bodyParser.json());
-    this.app.use(bodyParser.urlencoded({ extended: false }));
+    this.app.use(bodyParser.json({limit: '10mb'}));
+    this.app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }));
     this.app.use(cookieParser());
     this.app.use(express.static(path.join(__dirname, "public")));
     this.app.use((req, res, next)=> {

+ 17 - 10
recipes/src/components/ImageUploader/index.tsx

@@ -5,24 +5,31 @@ import Button from 'components/Button';
 import './styles.scss';
 import sample_image from 'sample.png';
 
+
 type ImageUploaderProps = {
-  onChange?: (file: File) => void;
+  onChange?: (file: string | ArrayBuffer | null) => void;
 };
 
 export const ImageUploader: React.FunctionComponent<ImageUploaderProps> = ({ onChange = () => {} }) => {
   const [ file, setFile ] = useState({
     name: '',
-    url: ''
+    image: ''
   });
   const fileInput: React.RefObject<HTMLInputElement> = useRef(null);
 
   const onChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
     if (e.target.files && e.target.files[0]) {
-      setFile({
-        url: URL.createObjectURL(e.target.files[0]),
-        name: e.target.files[0].name
-      });
-      onChange(e.target.files[0])
+      const file = e.target.files[0];
+      const reader = new FileReader();
+      reader.readAsDataURL(file);
+      reader.onload = () => {
+        const result = reader.result;
+        onChange(result)
+        setFile({
+          image: JSON.stringify(result),
+          name: file.name
+        });
+      }
     }
   }
 
@@ -30,10 +37,10 @@ export const ImageUploader: React.FunctionComponent<ImageUploaderProps> = ({ onC
     <div className='cbk-img-uploader'>
       <input type='file' onChange={onChangeFile} ref={fileInput} accept="image/*"/>
       {
-        file.url ? (
+        file.image ? (
           <div className='cbk-img-uploader__preview'
             style={{
-              backgroundImage: `url(${file.url})`
+              backgroundImage: `url(${file.image})`
             }}
           >
             <Button
@@ -42,7 +49,7 @@ export const ImageUploader: React.FunctionComponent<ImageUploaderProps> = ({ onC
               icon='clear'
               onClick={() => setFile({
                 name: '',
-                url: ''
+                image: ''
               }) }
             />
             <label>{file.name}</label>

+ 8 - 5
recipes/src/components/RecipeForm/index.tsx

@@ -12,7 +12,6 @@ import Dialog from 'components/DialogConverter';
 import TagInput from 'components/TagInput';
 import DurationPicker from 'components/DurationPicker';
 
-import sample_image from 'sample.png';
 import './styles.scss';
 
 type RecipeFormProps<T> = {
@@ -103,21 +102,25 @@ const RecipeForm = <T extends Recipe|DBRecipe>({ initialValues, onSubmit }: Reci
       enableReinitialize
       initialValues={initialValues}
       onSubmit={(values) => {
-        console.log('submit', values)
+        console.log(values);
+        onSubmit(values);
       }}
     >
       {
         ({setFieldValue, submitForm, values}) => {
           return (
           <Grid>
-            <Form className='cbk-recipe-form'>
+            <Form className='cbk-recipe-form' encType="multipart/form-data">
             <Row>
               <Cell columns={2}>
-                <ImageUploader/>
+                <ImageUploader
+                  onChange={(image)=> {
+                    setFieldValue('image', image)
+                  }}
+                />
               </Cell>
               <Cell columns={10}>
                 <FormikInput name='name' label='name' />
-        
                 <FormikTextarea name='summary' label='summary' />
               </Cell>
             </Row>

+ 2 - 0
recipes/src/types/recipes.ts

@@ -52,6 +52,7 @@ export const _recipe: Recipe = {
   summary: '',
   tags: [],
   course: [],
+  image: null
 }
 
 export interface Equivalences {
@@ -116,6 +117,7 @@ export default interface Recipe {
   summary: string,
   tags: string[],
   course: string[];
+  image?: any,
 }
 
 export interface DBRecipe extends Recipe {