diff --git a/README.md b/README.md index 3c3c1b3..53d33ba 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,10 @@ $ npm run build # Build the JS dependencies Ideally, Python dependencies should be installed in a virtual environment. -TODO: -- `npm run build` should handle prefix +If you serve the app from a subdirectory (and not the root of your domain), +you might want to run `API_URL=/subdir/ npm run build` instead of `npm run +build` to use the correct path to call the API. Note that the trailing slash +is important. ## Usage @@ -57,6 +59,9 @@ Additionnally, you can use `make dev` to spawn a development webserver to serve the JS frontend and auto-update/auto-reload when you make changes. The spawned JS server will be set up at `localhost:8081` and you should start the backend Python server at `localhost:8080` with `python -m cuizin` along it. +You can simply open the app at `localhost:8081` and start developping, it will +automatically call the API from the `python -m cuizin` process, on port +`8080`. ## License diff --git a/config/dev.env.js b/config/dev.env.js index 1e22973..dd74f6e 100644 --- a/config/dev.env.js +++ b/config/dev.env.js @@ -1,7 +1,9 @@ 'use strict' const merge = require('webpack-merge') +const process = require('process'); const prodEnv = require('./prod.env') module.exports = merge(prodEnv, { - NODE_ENV: '"development"' + NODE_ENV: '"development"', + API_URL: JSON.stringify(process.env.API_URL || "http://localhost:8080/"), }) diff --git a/config/prod.env.js b/config/prod.env.js index a6f9976..4616fd7 100644 --- a/config/prod.env.js +++ b/config/prod.env.js @@ -1,4 +1,7 @@ 'use strict' +const process = require('process'); + module.exports = { - NODE_ENV: '"production"' + NODE_ENV: '"production"', + API_URL: JSON.stringify(process.env.API_URL || null) } diff --git a/cuizin/db.py b/cuizin/db.py index 573dd7f..1027fd1 100644 --- a/cuizin/db.py +++ b/cuizin/db.py @@ -33,16 +33,25 @@ class Recipe(Model): """ Our base model for a recipe. """ - title = CharField() + # Name of the recipe + title = CharField(null=True) + # URL, should be unique url = CharField(null=True, unique=True) + # Author author = CharField(null=True) + # Picture as a binary blob picture = BlobField(null=True) + # Short description short_description = TextField(null=True) + # Number of persons as text, as it can be either "N persons" or "N parts" nb_person = TextField(null=True) + # Preparation and cooking times preparation_time = IntegerField(null=True) # In minutes cooking_time = IntegerField(null=True) # In minutes + # List of ingredients ingredients = JSONField(null=True) - instructions = TextField() + # Instructions + instructions = TextField(null=True) class Meta: database = database @@ -70,12 +79,13 @@ class Recipe(Model): serialized = model_to_dict(self) # Dump picture as a base64 string, compatible with HTML `src` attribute # for images. - picture_mime = ( - 'data:%s;base64' % magic.from_buffer(serialized['picture'], - mime=True) - ) - serialized['picture'] = '%s,%s' % ( - picture_mime, - base64.b64encode(serialized['picture']).decode('utf-8') - ) + if serialized['picture']: + picture_mime = ( + 'data:%s;base64' % magic.from_buffer(serialized['picture'], + mime=True) + ) + serialized['picture'] = '%s,%s' % ( + picture_mime, + base64.b64encode(serialized['picture']).decode('utf-8') + ) return serialized diff --git a/cuizin/js_src/components/Home.vue b/cuizin/js_src/components/Home.vue index 088c9a1..eab0ac4 100644 --- a/cuizin/js_src/components/Home.vue +++ b/cuizin/js_src/components/Home.vue @@ -49,7 +49,7 @@ export default { fetchRecipes() { this.isLoading = true; - fetch(`${constants.API_URL}/api/v1/recipes`) + fetch(`${constants.API_URL}api/v1/recipes`) .then(response => response.json()) .then((response) => { this.recipes = response.recipes; diff --git a/cuizin/js_src/components/New.vue b/cuizin/js_src/components/New.vue index b51bc19..d43e8b2 100644 --- a/cuizin/js_src/components/New.vue +++ b/cuizin/js_src/components/New.vue @@ -122,7 +122,7 @@ export default { methods: { submitImport() { this.disabledImport = true; - fetch(`${constants.API_URL}/api/v1/recipes`, { + fetch(`${constants.API_URL}api/v1/recipes`, { method: 'POST', body: JSON.stringify({ url: this.url, diff --git a/cuizin/js_src/components/Recipe.vue b/cuizin/js_src/components/Recipe.vue index c81f2d6..63b1ebe 100644 --- a/cuizin/js_src/components/Recipe.vue +++ b/cuizin/js_src/components/Recipe.vue @@ -54,7 +54,7 @@ export default { fetchRecipe() { this.isLoading = true; - fetch(`${constants.API_URL}/api/v1/recipe/${this.$route.params.recipeId}`) + fetch(`${constants.API_URL}api/v1/recipe/${this.$route.params.recipeId}`) .then(response => response.json()) .then((response) => { this.recipe = response.recipes[0]; @@ -62,7 +62,7 @@ export default { }); }, handleDelete() { - fetch(`${constants.API_URL}/api/v1/recipe/${this.$route.params.recipeId}`, { + fetch(`${constants.API_URL}api/v1/recipe/${this.$route.params.recipeId}`, { method: 'DELETE', }) .then(() => this.$router.replace('/')); diff --git a/cuizin/js_src/constants.js b/cuizin/js_src/constants.js index 4732511..4982031 100644 --- a/cuizin/js_src/constants.js +++ b/cuizin/js_src/constants.js @@ -1,2 +1 @@ -export const API_URL = 'http://localhost:8080'; // TODO: Should be coming from an env variable -export const FOOBAR = 'TODO'; // TODO +export const API_URL = process.env.API_URL || '/'; // eslint-disable-line import/prefer-default-export,no-use-before-define diff --git a/cuizin/scraping.py b/cuizin/scraping.py index 32e6fc1..c3a0c9b 100644 --- a/cuizin/scraping.py +++ b/cuizin/scraping.py @@ -47,8 +47,9 @@ def add_recipe(url): recipe.url = url break + # If we could not scrape anything, simply create an empty recipe storing + # the URL. if not recipe: - # TODO recipe = db.Recipe() recipe.url = url