small PDF export tweaks
This commit is contained in:
parent
0a6abf9688
commit
d506952602
@ -145,3 +145,7 @@ REVERSE_PROXY_AUTH=0
|
|||||||
#AUTH_LDAP_BIND_DN=
|
#AUTH_LDAP_BIND_DN=
|
||||||
#AUTH_LDAP_BIND_PASSWORD=
|
#AUTH_LDAP_BIND_PASSWORD=
|
||||||
#AUTH_LDAP_USER_SEARCH_BASE_DN=
|
#AUTH_LDAP_USER_SEARCH_BASE_DN=
|
||||||
|
|
||||||
|
# Enables exporting PDF (see export docs)
|
||||||
|
# Disabled by default, uncomment to enable
|
||||||
|
# ENABLE_PDF_EXPORT=1
|
@ -47,7 +47,7 @@ class UserPreferenceForm(forms.ModelForm):
|
|||||||
fields = (
|
fields = (
|
||||||
'default_unit', 'use_fractions', 'use_kj', 'theme', 'nav_color',
|
'default_unit', 'use_fractions', 'use_kj', 'theme', 'nav_color',
|
||||||
'sticky_navbar', 'default_page', 'show_recent', 'search_style',
|
'sticky_navbar', 'default_page', 'show_recent', 'search_style',
|
||||||
'plan_share', 'ingredient_decimals', 'comments',
|
'plan_share', 'ingredient_decimals', 'comments',
|
||||||
)
|
)
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
@ -496,7 +496,7 @@ class ShoppingPreferenceForm(forms.ModelForm):
|
|||||||
'mealplan_autoexclude_onhand': _('When adding a meal plan to the shopping list (manually or automatically), exclude ingredients that are on hand.'),
|
'mealplan_autoexclude_onhand': _('When adding a meal plan to the shopping list (manually or automatically), exclude ingredients that are on hand.'),
|
||||||
'default_delay': _('Default number of hours to delay a shopping list entry.'),
|
'default_delay': _('Default number of hours to delay a shopping list entry.'),
|
||||||
'filter_to_supermarket': _('Filter shopping list to only include supermarket categories.'),
|
'filter_to_supermarket': _('Filter shopping list to only include supermarket categories.'),
|
||||||
'shopping_recent_days': _('Days of recent shopping list entries to display.'),
|
'shopping_recent_days': _('Days of recent shopping list entries to display.'),
|
||||||
'shopping_add_onhand': _("Mark food 'On Hand' when checked off shopping list."),
|
'shopping_add_onhand': _("Mark food 'On Hand' when checked off shopping list."),
|
||||||
'csv_delim': _('Delimiter to use for CSV exports.'),
|
'csv_delim': _('Delimiter to use for CSV exports.'),
|
||||||
'csv_prefix': _('Prefix to add when copying list to the clipboard.'),
|
'csv_prefix': _('Prefix to add when copying list to the clipboard.'),
|
||||||
|
@ -19,10 +19,6 @@ class PDFexport(Integration):
|
|||||||
def get_recipe_from_file(self, file):
|
def get_recipe_from_file(self, file):
|
||||||
raise NotImplementedError('Method not implemented in storage integration')
|
raise NotImplementedError('Method not implemented in storage integration')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def get_files_from_recipes_async(self, recipes, cookie):
|
async def get_files_from_recipes_async(self, recipes, cookie):
|
||||||
cmd = runserver.Command()
|
cmd = runserver.Command()
|
||||||
|
|
||||||
@ -33,15 +29,15 @@ class PDFexport(Integration):
|
|||||||
ignoreHTTPSErrors=True
|
ignoreHTTPSErrors=True
|
||||||
)
|
)
|
||||||
|
|
||||||
cookies = {'domain': cmd.default_addr, 'name': 'sessionid', 'value': cookie['sessionid'],}
|
cookies = {'domain': cmd.default_addr, 'name': 'sessionid', 'value': cookie['sessionid'], }
|
||||||
options = { 'format': 'letter',
|
options = {'format': 'letter',
|
||||||
'margin': {
|
'margin': {
|
||||||
'top': '0.75in',
|
'top': '0.75in',
|
||||||
'bottom': '0.75in',
|
'bottom': '0.75in',
|
||||||
'left': '0.75in',
|
'left': '0.75in',
|
||||||
'right': '0.75in',
|
'right': '0.75in',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
page = await browser.newPage()
|
page = await browser.newPage()
|
||||||
await page.emulateMedia('print')
|
await page.emulateMedia('print')
|
||||||
@ -49,14 +45,11 @@ class PDFexport(Integration):
|
|||||||
|
|
||||||
files = []
|
files = []
|
||||||
for recipe in recipes:
|
for recipe in recipes:
|
||||||
await page.goto('http://'+cmd.default_addr+':'+cmd.default_port+'/view/recipe/'+str(recipe.id), {'waitUntil': 'networkidle0',})
|
await page.goto('http://' + cmd.default_addr + ':' + cmd.default_port + '/view/recipe/' + str(recipe.id), {'waitUntil': 'networkidle0', })
|
||||||
files.append([ recipe.name+'.pdf', await page.pdf(options) ])
|
files.append([recipe.name + '.pdf', await page.pdf(options)])
|
||||||
|
|
||||||
|
|
||||||
await browser.close()
|
await browser.close()
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_files_from_recipes(self, recipes, cookie):
|
def get_files_from_recipes(self, recipes, cookie):
|
||||||
return asyncio.run(self.get_files_from_recipes_async(recipes, cookie))
|
return asyncio.run(self.get_files_from_recipes_async(recipes, cookie))
|
||||||
|
@ -30,6 +30,7 @@ from cookbook.integration.rezkonv import RezKonv
|
|||||||
from cookbook.integration.saffron import Saffron
|
from cookbook.integration.saffron import Saffron
|
||||||
from cookbook.integration.pdfexport import PDFexport
|
from cookbook.integration.pdfexport import PDFexport
|
||||||
from cookbook.models import Recipe, ImportLog, UserPreference
|
from cookbook.models import Recipe, ImportLog, UserPreference
|
||||||
|
from recipes import settings
|
||||||
|
|
||||||
|
|
||||||
def get_integration(request, export_type):
|
def get_integration(request, export_type):
|
||||||
@ -121,6 +122,10 @@ def export_recipe(request):
|
|||||||
recipes = form.cleaned_data['recipes']
|
recipes = form.cleaned_data['recipes']
|
||||||
if form.cleaned_data['all']:
|
if form.cleaned_data['all']:
|
||||||
recipes = Recipe.objects.filter(space=request.space, internal=True).all()
|
recipes = Recipe.objects.filter(space=request.space, internal=True).all()
|
||||||
|
|
||||||
|
if form.cleaned_data['type'] == ImportExportBase.PDF and not settings.ENABLE_PDF_EXPORT:
|
||||||
|
messages.add_message(request, messages.ERROR, _('The PDF Exporter is not enabled on this instance as it is still in an experimental state.'))
|
||||||
|
return render(request, 'export.html', {'form': form})
|
||||||
integration = get_integration(request, form.cleaned_data['type'])
|
integration = get_integration(request, form.cleaned_data['type'])
|
||||||
return integration.do_export(recipes)
|
return integration.do_export(recipes)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
|
@ -20,24 +20,25 @@ if your favorite one is missing.
|
|||||||
|
|
||||||
Overview of the capabilities of the different integrations.
|
Overview of the capabilities of the different integrations.
|
||||||
|
|
||||||
| Integration | Import | Export | Images |
|
| Integration | Import | Export | Images |
|
||||||
| ----------- | ------ | ------ | ------ |
|
|--------------------| ------ | ------ | ------ |
|
||||||
| Default | ✔️ | ✔️ | ✔️ |
|
| Default | ✔️ | ✔️ | ✔️ |
|
||||||
| Nextcloud | ✔️ | ⌚ | ✔️ |
|
| Nextcloud | ✔️ | ⌚ | ✔️ |
|
||||||
| Mealie | ✔️ | ⌚ | ✔️ |
|
| Mealie | ✔️ | ⌚ | ✔️ |
|
||||||
| Chowdown | ✔️ | ⌚ | ✔️ |
|
| Chowdown | ✔️ | ⌚ | ✔️ |
|
||||||
| Safron | ✔️ | ⌚ | ❌ |
|
| Safron | ✔️ | ✔ | ❌ |
|
||||||
| Paprika | ✔️ | ⌚ | ✔️ |
|
| Paprika | ✔️ | ⌚ | ✔️ |
|
||||||
| ChefTap | ✔️ | ❌ | ❌ |
|
| ChefTap | ✔️ | ❌ | ❌ |
|
||||||
| Pepperplate | ✔️ | ⌚ | ❌ |
|
| Pepperplate | ✔️ | ⌚ | ❌ |
|
||||||
| RecipeSage | ✔️ | ✔️ | ✔️ |
|
| RecipeSage | ✔️ | ✔️ | ✔️ |
|
||||||
| Domestica | ✔️ | ⌚ | ✔️ |
|
| Domestica | ✔️ | ⌚ | ✔️ |
|
||||||
| MealMaster | ✔️ | ❌ | ❌ |
|
| MealMaster | ✔️ | ❌ | ❌ |
|
||||||
| RezKonv | ✔️ | ❌ | ❌ |
|
| RezKonv | ✔️ | ❌ | ❌ |
|
||||||
| OpenEats | ✔️ | ❌ | ⌚ |
|
| OpenEats | ✔️ | ❌ | ⌚ |
|
||||||
| Plantoeat | ✔️ | ❌ | ✔ |
|
| Plantoeat | ✔️ | ❌ | ✔ |
|
||||||
| CookBookApp | ✔️ | ⌚ | ✔️ |
|
| CookBookApp | ✔️ | ⌚ | ✔️ |
|
||||||
| CopyMeThat | ✔️ | ❌ | ✔️ |
|
| CopyMeThat | ✔️ | ❌ | ✔️ |
|
||||||
|
| PDF (experimental) | ⌚️ | ✔ | ✔️ |
|
||||||
|
|
||||||
✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
|
✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
|
||||||
|
|
||||||
@ -222,4 +223,14 @@ CookBookApp can export .zip files containing .html files. Upload the entire ZIP
|
|||||||
|
|
||||||
## CopyMeThat
|
## CopyMeThat
|
||||||
|
|
||||||
CopyMeThat can export .zip files containing an `.html` file as well as a folder containing all the images. Upload the entire ZIP to Tandoor to import all included recipes.
|
CopyMeThat can export .zip files containing an `.html` file as well as a folder containing all the images. Upload the entire ZIP to Tandoor to import all included recipes.
|
||||||
|
|
||||||
|
## PDF
|
||||||
|
|
||||||
|
The PDF Exporter is an experimental feature that uses the puppeteer browser renderer to render each recipe and export it to PDF.
|
||||||
|
For that to work it downloads a chromium binary of about 140 MB to your server and then renders the PDF files using that.
|
||||||
|
|
||||||
|
Since that is something some server administrators might not want there the PDF exporter is disabled by default and can be enabled with `ENABLE_PDF_EXPORT=1` in `.env`.
|
||||||
|
|
||||||
|
See [this issue](https://github.com/TandoorRecipes/recipes/pull/1211) for more discussion on this and
|
||||||
|
[this issue](https://github.com/TandoorRecipes/recipes/issues/781) for the future plans to support server side rendering.
|
@ -137,6 +137,8 @@ ENABLE_SIGNUP = bool(int(os.getenv('ENABLE_SIGNUP', False)))
|
|||||||
|
|
||||||
ENABLE_METRICS = bool(int(os.getenv('ENABLE_METRICS', False)))
|
ENABLE_METRICS = bool(int(os.getenv('ENABLE_METRICS', False)))
|
||||||
|
|
||||||
|
ENABLE_PDF_EXPORT = bool(int(os.getenv('ENABLE_PDF_EXPORT', False)))
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'corsheaders.middleware.CorsMiddleware',
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
Loading…
Reference in New Issue
Block a user