Merge branch 'develop' into bookmarklet

This commit is contained in:
vabene1111 2021-05-02 17:41:38 +02:00 committed by GitHub
commit c4880bf5b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 49 deletions

View File

@ -9,14 +9,14 @@ jobs:
strategy: strategy:
max-parallel: 4 max-parallel: 4
matrix: matrix:
python-version: [3.8] python-version: [3.9]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Set up Python 3.8 - name: Set up Python 3.9
uses: actions/setup-python@v1 uses: actions/setup-python@v1
with: with:
python-version: 3.8 python-version: 3.9
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip

View File

@ -18,7 +18,7 @@
<excludeFolder url="file://$MODULE_DIR$/staticfiles" /> <excludeFolder url="file://$MODULE_DIR$/staticfiles" />
<excludeFolder url="file://$MODULE_DIR$/venv" /> <excludeFolder url="file://$MODULE_DIR$/venv" />
</content> </content>
<orderEntry type="jdk" jdkName="Python 3.8 (recipes)" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.9 (recipes)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="TemplatesService"> <component name="TemplatesService">

View File

@ -2,6 +2,7 @@ import random
import re import re
from isodate import parse_duration as iso_parse_duration from isodate import parse_duration as iso_parse_duration
from isodate.isoerror import ISO8601Error from isodate.isoerror import ISO8601Error
from recipe_scrapers._exceptions import ElementNotFoundInHtml
from cookbook.helper.ingredient_parser import parse as parse_single_ingredient from cookbook.helper.ingredient_parser import parse as parse_single_ingredient
from cookbook.models import Keyword from cookbook.models import Keyword
@ -17,12 +18,12 @@ def get_from_scraper(scrape, space):
recipe_json = {} recipe_json = {}
try: try:
recipe_json['name'] = parse_name(scrape.title() or scrape.schema.data.get('name') or '') recipe_json['name'] = parse_name(scrape.title() or scrape.schema.data.get('name') or '')
except (TypeError, AttributeError): except (TypeError, AttributeError,ElementNotFoundInHtml):
recipe_json['name'] = '' recipe_json['name'] = ''
try: try:
description = scrape.schema.data.get("description") or '' description = scrape.schema.data.get("description") or ''
except AttributeError: except (AttributeError,ElementNotFoundInHtml):
description = '' description = ''
recipe_json['description'] = parse_description(description) recipe_json['description'] = parse_description(description)
@ -30,21 +31,27 @@ def get_from_scraper(scrape, space):
try: try:
servings = scrape.yields() servings = scrape.yields()
servings = int(re.findall(r'\b\d+\b', servings)[0]) servings = int(re.findall(r'\b\d+\b', servings)[0])
except (AttributeError, ValueError, IndexError): except (AttributeError,ElementNotFoundInHtml, ValueError, IndexError):
servings = 1 servings = 1
recipe_json['servings'] = servings recipe_json['servings'] = servings
recipe_json['prepTime'] = get_minutes(scrape.schema.data.get("prepTime")) or 0 try:
recipe_json['cookTime'] = get_minutes(scrape.schema.data.get("cookTime")) or 0 recipe_json['prepTime'] = get_minutes(scrape.schema.data.get("prepTime")) or 0
except (AttributeError, ElementNotFoundInHtml):
recipe_json['prepTime'] = 0
try:
recipe_json['cookTime'] = get_minutes(scrape.schema.data.get("cookTime")) or 0
except (AttributeError, ElementNotFoundInHtml):
recipe_json['cookTime'] = 0
if recipe_json['cookTime'] + recipe_json['prepTime'] == 0: if recipe_json['cookTime'] + recipe_json['prepTime'] == 0:
try: try:
recipe_json['prepTime'] = get_minutes(scrape.total_time()) or 0 recipe_json['prepTime'] = get_minutes(scrape.total_time()) or 0
except AttributeError: except (AttributeError,ElementNotFoundInHtml):
pass pass
try: try:
recipe_json['image'] = parse_image(scrape.image()) or '' recipe_json['image'] = parse_image(scrape.image()) or ''
except (AttributeError, TypeError, SchemaOrgException): except (AttributeError,ElementNotFoundInHtml, TypeError, SchemaOrgException):
recipe_json['image'] = '' recipe_json['image'] = ''
keywords = [] keywords = []
@ -56,7 +63,7 @@ def get_from_scraper(scrape, space):
if scrape.schema.data.get('recipeCuisine'): if scrape.schema.data.get('recipeCuisine'):
keywords += listify_keywords(scrape.schema.data.get("recipeCuisine")) keywords += listify_keywords(scrape.schema.data.get("recipeCuisine"))
recipe_json['keywords'] = parse_keywords(list(set(map(str.casefold, keywords))), space) recipe_json['keywords'] = parse_keywords(list(set(map(str.casefold, keywords))), space)
except AttributeError: except (AttributeError,ElementNotFoundInHtml):
recipe_json['keywords'] = keywords recipe_json['keywords'] = keywords
try: try:
@ -97,12 +104,12 @@ def get_from_scraper(scrape, space):
} }
) )
recipe_json['recipeIngredient'] = ingredients recipe_json['recipeIngredient'] = ingredients
except AttributeError: except (AttributeError,ElementNotFoundInHtml):
recipe_json['recipeIngredient'] = ingredients recipe_json['recipeIngredient'] = ingredients
try: try:
recipe_json['recipeInstructions'] = parse_instructions(scrape.instructions()) recipe_json['recipeInstructions'] = parse_instructions(scrape.instructions())
except AttributeError: except (AttributeError,ElementNotFoundInHtml):
recipe_json['recipeInstructions'] = "" recipe_json['recipeInstructions'] = ""
if scrape.url: if scrape.url:

View File

@ -83,6 +83,25 @@
<label class="btn btn-outline-info btn-sm" @click="recipe_app='SAFRON'"> <label class="btn btn-outline-info btn-sm" @click="recipe_app='SAFRON'">
<input type="radio" autocomplete="off"> Safron <input type="radio" autocomplete="off"> Safron
</label> </label>
<label class="btn btn-outline-info btn-sm" @click="recipe_app='CHEFTAP'">
<input type="radio" autocomplete="off"> Cheftap
</label>
<label class="btn btn-outline-info btn-sm" @click="recipe_app='PEPPERPLATE'">
<input type="radio" autocomplete="off"> Pepperplate
</label>
<label class="btn btn-outline-info btn-sm" @click="recipe_app='RECIPESAGE'">
<input type="radio" autocomplete="off"> Recipesage
</label>
<label class="btn btn-outline-info btn-sm" @click="recipe_app='DOMESTICA'">
<input type="radio" autocomplete="off"> Domestica
</label>
<label class="btn btn-outline-info btn-sm" @click="recipe_app='MEALMASTER'">
<input type="radio" autocomplete="off"> Mealmaster
</label>
<label class="btn btn-outline-info btn-sm" @click="recipe_app='REZKONV'">
<input type="radio" autocomplete="off"> Rezkonv
</label>
</div> </div>
<b-form-file <b-form-file
class="my-2" class="my-2"
@ -113,7 +132,7 @@
</textarea> </textarea>
</div> </div>
<button @click="loadRecipe()" class="btn btn-primary shadow-none" type="button" <button @click="loadRecipe()" class="btn btn-primary shadow-none" type="button"
id="id_btn_app"><i class="fas fa-code"></i> {% trans 'Import' %} id="id_btn_app"><i class="fas fa-code"></i> {% trans 'Import' %}
</button> </button>
</div> </div>
</div> </div>
@ -274,18 +293,18 @@
</div> </div>
<br/> <br/>
<!-- end of preview card --> <!-- end of preview card -->
<button @click="showRecipe()" class="btn btn-primary shadow-none" type="button" <button @click="showRecipe()" class="btn btn-primary shadow-none" type="button" style="margin-bottom: 2vh"
id="id_btn_json"><i class="fas fa-code"></i> {% trans 'Import' %} id="id_btn_json"><i class="fas fa-code"></i> {% trans 'Import' %}
</button> </button>
</div> </div>
<!-- start of source data --> <!-- start of source data -->
<div class="col" style="max-width:50%"> <div class="col" style="max-width:50%;">
<div class="card card-border-primary"> <div class="card card-border-primary sticky-top" style="z-index: 100;">
<div class="card-header"> <div class="card-header">
<h3>{% trans 'Discovered Attributes' %}</h3> <h3>{% trans 'Discovered Attributes' %}</h3>
<div class='small text-muted'> <div class='small text-muted'>
{% trans 'Drag recipe attributes from below into the appropriate box on the left. Click any node to display its full properties.' %} {% trans 'Drag recipe attributes from below into the appropriate box on the left. Click any node to display its full properties.' %}
</div> </div>
</div> </div>
<div class="btn-group btn-group-toggle" data-toggle="buttons"> <div class="btn-group btn-group-toggle" data-toggle="buttons">
@ -299,8 +318,8 @@
<input type="radio" autocomplete="off"> images <input type="radio" autocomplete="off"> images
</label> </label>
</div> </div>
<i :class="[show_blank ? 'fa-chevron-up' : 'fa-chevron-down', 'fas']" <i :class="[show_blank ? 'fa-chevron-up' : 'fa-chevron-down', 'fas']"
style="cursor:pointer;" style="cursor:pointer;"
@click="show_blank=!show_blank" @click="show_blank=!show_blank"
title="{% trans 'Show Blank Field' %}"></i> title="{% trans 'Show Blank Field' %}"></i>
<div class="card-body p-1"> <div class="card-body p-1">
@ -312,9 +331,9 @@
</div> </div>
<div class="small text-muted">{% trans 'Items dragged to Blank Field will be appended.'%}</div> <div class="small text-muted">{% trans 'Items dragged to Blank Field will be appended.'%}</div>
</div> </div>
<div class="card-body drop-zone" <div class="card-body drop-zone"
@drop="replacePreview('blank', $event)" @drop="replacePreview('blank', $event)"
@dragover.prevent @dragover.prevent
@dragenter.prevent @dragenter.prevent
draggable draggable
@dragstart="htmlDragStart($event)"> @dragstart="htmlDragStart($event)">
@ -332,7 +351,7 @@
<div class="col" @click.ctrl="customItemClickWithCtrl"> <div class="col" @click.ctrl="customItemClickWithCtrl">
<div class="row clearfix" style="width:100%" > <div class="row clearfix" style="width:100%" >
<div class="col-es" style="align-right"> <div class="col-es" style="align-right">
<button style="border: 0px; background-color: transparent; cursor: pointer;" <button style="border: 0px; background-color: transparent; cursor: pointer;"
@click="deleteNode(_.vm, _.model, $event)"><i class="fas fa-minus-square" style="color:red"></i></button> @click="deleteNode(_.vm, _.model, $event)"><i class="fas fa-minus-square" style="color:red"></i></button>
</div> </div>
<div class="col overflow-hidden"> <div class="col overflow-hidden">
@ -343,17 +362,17 @@
</div> </div>
</div> </div>
</div> </div>
</template> </template>
</v-jstree> </v-jstree>
<!-- start of html data --> <!-- start of html data -->
<div v-if="preview_type=='html'"> <div v-if="preview_type=='html'">
<ul class="list-group list-group-flush" v-for="(txt, key) in recipe_html"> <ul class="list-group list-group-flush" v-for="(txt, key) in recipe_html">
<div class="list-group-item bg-light m-0 small" <div class="list-group-item bg-light m-0 small"
draggable draggable
@dragstart="htmlDragStart($event)" @dragstart="htmlDragStart($event)"
style="display:flex; justify-content:space-between;"> style="display:flex; justify-content:space-between;">
[[txt]] [[txt]]
<i class="fas fa-minus-square" style="cursor:pointer; color:red" @click="$delete(recipe_html, key)" title="{% trans 'Delete Text'%}"></i> <i class="fas fa-minus-square" style="cursor:pointer; color:red" @click="$delete(recipe_html, key)" title="{% trans 'Delete Text'%}"></i>
</div> </div>
</ul> </ul>
@ -361,10 +380,10 @@
<!-- start of images --> <!-- start of images -->
<div v-if="preview_type=='image'"> <div v-if="preview_type=='image'">
<ul class="list-group list-group-flush" v-for="(img, key) in images"> <ul class="list-group list-group-flush" v-for="(img, key) in images">
<div class="list-group-item bg-light m-0 small" <div class="list-group-item bg-light m-0 small"
draggable draggable
@dragstart="imageDragStart($event)" @dragstart="imageDragStart($event)"
style="display:flex; justify-content:space-between;"> style="display:flex; justify-content:space-between;">
<img class="card-img" v-bind:src=[[img]] alt="Image"> <img class="card-img" v-bind:src=[[img]] alt="Image">
<i class="fas fa-minus-square" style="cursor:pointer; color:red" @click="$delete(images, key)" title="{% trans 'Delete image'%}"></i> <i class="fas fa-minus-square" style="cursor:pointer; color:red" @click="$delete(images, key)" title="{% trans 'Delete image'%}"></i>
</div> </div>

View File

@ -16,10 +16,6 @@ from django.http import FileResponse, HttpResponse, JsonResponse
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from icalendar import Calendar, Event from icalendar import Calendar, Event
from rest_framework import decorators, viewsets
from rest_framework.exceptions import APIException, PermissionDenied
from recipe_scrapers import scrape_me, WebsiteNotImplementedError, NoSchemaFoundInWildMode from recipe_scrapers import scrape_me, WebsiteNotImplementedError, NoSchemaFoundInWildMode
from rest_framework import decorators, viewsets from rest_framework import decorators, viewsets
from rest_framework.exceptions import APIException, PermissionDenied from rest_framework.exceptions import APIException, PermissionDenied
@ -34,13 +30,11 @@ from cookbook.helper.ingredient_parser import parse
from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest, from cookbook.helper.permission_helper import (CustomIsAdmin, CustomIsGuest,
CustomIsOwner, CustomIsShare, CustomIsOwner, CustomIsShare,
CustomIsShared, CustomIsUser, CustomIsShared, CustomIsUser,
group_required)
group_required, share_link_valid)
from cookbook.helper.recipe_html_import import get_recipe_from_source from cookbook.helper.recipe_html_import import get_recipe_from_source
from cookbook.helper.recipe_url_import import get_from_scraper
from cookbook.helper.recipe_search import search_recipes
from cookbook.helper.recipe_url_import import get_from_html, get_from_scraper, find_recipe_json
from cookbook.helper.recipe_search import search_recipes
from cookbook.helper.recipe_url_import import get_from_scraper
from cookbook.models import (CookLog, Food, Ingredient, Keyword, MealPlan, from cookbook.models import (CookLog, Food, Ingredient, Keyword, MealPlan,
MealType, Recipe, RecipeBook, ShoppingList, MealType, Recipe, RecipeBook, ShoppingList,
ShoppingListEntry, ShoppingListRecipe, Step, ShoppingListEntry, ShoppingListRecipe, Step,

View File

@ -3,7 +3,7 @@
These intructions are inspired from a standard django/gunicorn/postgresql instructions ([for example](https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04)) These intructions are inspired from a standard django/gunicorn/postgresql instructions ([for example](https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04))
!!! warning !!! warning
Be sure to use pyton3.8 and pip related to python 3.8. Depending on your distribution calling `python` or `pip` will use python2 instead of pyton 3.8. Be sure to use pyton3.9 and pip related to python 3.9. Depending on your distribution calling `python` or `pip` will use python2 instead of pyton 3.9.
## Prerequisites ## Prerequisites
@ -12,7 +12,7 @@ These intructions are inspired from a standard django/gunicorn/postgresql instru
Get the last version from the repository: `git clone https://github.com/vabene1111/recipes.git -b master` Get the last version from the repository: `git clone https://github.com/vabene1111/recipes.git -b master`
Install postgresql requirements: `sudo apt install libpq-dev postgresql` Install postgresql requirements: `sudo apt install libpq-dev postgresql`
Install project requirements: `pip3.8 install -r requirements.txt` Install project requirements: `pip3.9 install -r requirements.txt`
## Setup postgresql ## Setup postgresql
@ -44,11 +44,11 @@ wget https://raw.githubusercontent.com/vabene1111/recipes/develop/.env.template
Execute `export $(cat .env |grep "^[^#]" | xargs)` to load variables from `.env` Execute `export $(cat .env |grep "^[^#]" | xargs)` to load variables from `.env`
Execute `/python3.8 manage.py migrate` Execute `/python3.9 manage.py migrate`
and revert superuser from postgres: `sudo -u postgres psql` and `ALTER USER djangouser WITH NOSUPERUSER;` and revert superuser from postgres: `sudo -u postgres psql` and `ALTER USER djangouser WITH NOSUPERUSER;`
Generate static files: `python3.8 manage.py collectstatic` and remember the folder where files have been copied. Generate static files: `python3.9 manage.py collectstatic` and remember the folder where files have been copied.
## Setup web services ## Setup web services
@ -70,7 +70,7 @@ RestartSec=3
Group=www-data Group=www-data
WorkingDirectory=/media/data/recipes WorkingDirectory=/media/data/recipes
EnvironmentFile=/media/data/recipes/.env EnvironmentFile=/media/data/recipes/.env
ExecStart=/opt/.pyenv/versions/3.8.5/bin/gunicorn --error-logfile /tmp/gunicorn_err.log --log-level debug --capture-output --bind unix:/media/data/recipes/recipes.sock recipes.wsgi:application ExecStart=/opt/.pyenv/versions/3.9/bin/gunicorn --error-logfile /tmp/gunicorn_err.log --log-level debug --capture-output --bind unix:/media/data/recipes/recipes.sock recipes.wsgi:application
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -1,7 +1,7 @@
!!! info "Community Contributed" !!! info "Community Contributed"
The examples in this section were contributed by members of the community. The examples in this section were contributed by members of the community.
This page especially contains some setups that might help you if you really want to go down a certain path but none This page especially contains some setups that might help you if you really want to go down a certain path but none
of the examples are supported (as i simply am not able to give you support for them). of the examples are supported (as I simply am not able to give you support for them).
## Apache + Traefik + Sub-Path ## Apache + Traefik + Sub-Path

View File

@ -31,7 +31,7 @@ Jinja2==2.11.3
django-webpack-loader==0.7.0 django-webpack-loader==0.7.0
django-js-reverse==0.9.1 django-js-reverse==0.9.1
django-allauth==0.44.0 django-allauth==0.44.0
recipe-scrapers==13.1.1 recipe-scrapers==13.2.1
django-scopes==1.2.0 django-scopes==1.2.0
pytest==6.2.3 pytest==6.2.3
pytest-django==4.2.0 pytest-django==4.2.0