From 55ba568f3cfbbda4cb86d4e586192ac1a2fd5f66 Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 9 Mar 2021 11:29:10 -0600 Subject: [PATCH] import raw json/html --- cookbook/helper/recipe_raw_import.py | 98 +++++ cookbook/templates/import_json.html | 286 +++++++++++++++ cookbook/templates/import_json_working.html | 384 ++++++++++++++++++++ cookbook/urls.py | 4 +- cookbook/views/api.py | 13 +- cookbook/views/import_export.py | 9 +- 6 files changed, 789 insertions(+), 5 deletions(-) create mode 100644 cookbook/helper/recipe_raw_import.py create mode 100644 cookbook/templates/import_json.html create mode 100644 cookbook/templates/import_json_working.html diff --git a/cookbook/helper/recipe_raw_import.py b/cookbook/helper/recipe_raw_import.py new file mode 100644 index 000000000..07083843d --- /dev/null +++ b/cookbook/helper/recipe_raw_import.py @@ -0,0 +1,98 @@ + +# %% +import json + +from bs4 import BeautifulSoup +# from cookbook.helper.ingredient_parser import parse as parse_ingredient +from cookbook.helper import recipe_url_import as helper +from django.http import JsonResponse +from django.utils.dateparse import parse_duration + + +# %% + +# %% +def get_from_raw(raw_text): + def build_node(k, v): + if isinstance(v, dict): + node = { + 'name': k, + 'value': k, + 'children': get_children_dict(v) + } + elif isinstance(v, list): + node = { + 'name': k, + 'value': k, + 'children': get_children_list(v) + } + else: + node = { + 'name': k + ": " + str(v), + 'value': str(v) + } + return node + + def get_children_dict(children): + kid_list = [] + for k, v in children.items(): + kid_list.append(build_node(k, v)) + return kid_list + + def get_children_list(children): + kid_list = [] + for kid in children: + if type(kid) == list: + node = { + 'name': "unknown list", + 'value': "unknown list", + 'children': get_children_list(kid) + } + kid_list.append(node) + elif type(kid) == dict: + for k, v in kid.items(): + kid_list.append(build_node(k, v)) + else: + kid_list.append({ + 'name': kid, + 'value': kid + }) + return kid_list + + recipe_items = ['recipeIngredient', 'keywords', 'recipeInstructions', 'image', + 'cookTime', 'prepTime', 'servings', 'name'] + extra_items = ['recipeYield', 'title', 'recipeCategory', 'recipeCuisine'] + + soup = BeautifulSoup(raw_text, "html.parser") + recipe_json = {} + recipe_tree = [] + # first try finding ld+json as its most common + for ld in soup.find_all('script', type='application/ld+json'): + ld_json = helper.find_recipe_json(json.loads(ld.string), '') + for item in recipe_items: + if item in ld_json: + recipe_json[item] = ld_json[item] + recipe_items.remove(item) + del ld_json[item] + for k, v in ld_json.items(): + if isinstance(v, dict): + node = { + 'name': k, + 'value': k, + 'children': get_children_dict(v) + } + elif isinstance(v, list): + node = { + 'name': k, + 'value': k, + 'children': get_children_list(v) + } + else: + node = { + 'name': k + ": " + str(v), + 'value': str(v) + } + recipe_tree.append(node) + # TODO put recipe_tree and json_recipe in the JSON response + print(recipe_tree) + return recipe_json, recipe_tree diff --git a/cookbook/templates/import_json.html b/cookbook/templates/import_json.html new file mode 100644 index 000000000..e71e77d50 --- /dev/null +++ b/cookbook/templates/import_json.html @@ -0,0 +1,286 @@ +{% extends "base.html" %} +{% load crispy_forms_filters %} +{% load i18n %} +{% load static %} + +{% block title %}{% trans 'Import Recipe' %}{% endblock %} + +{% block extra_head %} + {% include 'include/vue_base.html' %} + + + + + +{% endblock %} + + +{% block content %} +
+
+

{% trans 'Import From Source' %}

+
+ +
+ Simply paste a web page source or JSON document into this textarea and click import. +
+ +
+ +
+ +
+
+ +
+ + +
+ + + + +
+ +
+ +{% endblock %} + +{% block script %} + + + + +{% endblock %} \ No newline at end of file diff --git a/cookbook/templates/import_json_working.html b/cookbook/templates/import_json_working.html new file mode 100644 index 000000000..b1e2e2bda --- /dev/null +++ b/cookbook/templates/import_json_working.html @@ -0,0 +1,384 @@ +{% extends "base.html" %} +{% load crispy_forms_filters %} +{% load i18n %} +{% load static %} + +{% block title %}{% trans 'Import Recipe' %}{% endblock %} + +{% block extra_head %} + {% include 'include/vue_base.html' %} + + + + + +{% endblock %} + + +{% block content %} +
+
+

{% trans 'Import From Source' %}

+
+ +
+ Simply paste a web page source or JSON document into this textarea and click import. +
+ +
+ +
+ +
+
+ +
+ + +
+ + + + +
+ +
+ +{% endblock %} + +{% block script %} + + + + +{% endblock %} \ No newline at end of file diff --git a/cookbook/urls.py b/cookbook/urls.py index 925e8bfb1..a3dc663db 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -59,7 +59,7 @@ urlpatterns = [ path('test2/', views.test2, name='view_test2'), path('import/', import_export.import_recipe, name='view_import'), - path('import-response//', import_export.import_response, name='view_import_response'), + path('import/json/', import_export.import_json, name='view_json_import'), path('export/', import_export.export_recipe, name='view_export'), path('view/recipe/', views.recipe_view, name='view_recipe'), @@ -94,7 +94,7 @@ urlpatterns = [ path('api/log_cooking//', api.log_cooking, name='api_log_cooking'), path('api/plan-ical///', api.get_plan_ical, name='api_get_plan_ical'), path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'), - path('api/recipe-from-json/', api.recipe_from_json, name='api_recipe_from_json'), + path('api/recipe-from-raw/', api.recipe_from_raw, name='api_recipe_from_raw'), path('api/backup/', api.get_backup, name='api_backup'), path('api/ingredient-from-string/', api.ingredient_from_string, name='api_ingredient_from_string'), diff --git a/cookbook/views/api.py b/cookbook/views/api.py index f48dbb0e6..b460b6972 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -35,7 +35,8 @@ from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest, CustomIsOwner, CustomIsShare, CustomIsShared, CustomIsUser, group_required) -from cookbook.helper.recipe_url_import import get_from_html, find_recipe_json +from cookbook.helper.recipe_url_import import get_from_html +from cookbook.helper.recipe_raw_import import get_from_raw from cookbook.models import (CookLog, Food, Ingredient, Keyword, MealPlan, MealType, Recipe, RecipeBook, ShoppingList, ShoppingListEntry, ShoppingListRecipe, Step, @@ -696,6 +697,16 @@ def recipe_from_url(request): ) +@group_required('user') +def recipe_from_raw(request): + raw_text = request.POST['raw_text'] + recipe_json, recipe_tree = get_from_raw(raw_text) + return JsonResponse({ + 'recipe_tree': recipe_tree, + 'recipe_json': recipe_json + }) + + @group_required('admin') def get_backup(request): if not request.user.is_superuser: diff --git a/cookbook/views/import_export.py b/cookbook/views/import_export.py index d0b6a1150..52fb2d2c1 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -109,5 +109,10 @@ def export_recipe(request): @group_required('user') -def import_response(request, pk): - return render(request, 'import_response.html', {'pk': pk}) +def import_json(request): + if request.method == "POST": + return True + else: + pass + + return render(request, 'import_json.html')