Compare commits

..

8 Commits
0.6.4 ... 0.6.5

Author SHA1 Message Date
vabene1111
c7046bc705 fixed markdown urlize 2020-04-26 15:52:07 +02:00
vabene1111
52946a8e4c fixed broken emoji 2020-04-26 00:29:56 +02:00
vabene1111
dd6b77e029 added screenshots + refactor preview + moved docu 2020-04-26 00:28:14 +02:00
vabene1111
396c1f3d5f added tooltips to recipe view 2020-04-25 23:35:01 +02:00
vabene1111
379d5a5177 import export cleanup + features 2020-04-25 23:32:15 +02:00
vabene1111
85a4d5d432 basic import export working 2020-04-25 22:26:59 +02:00
vabene1111
43eb10e488 added basic exporting capability 2020-04-25 22:05:55 +02:00
vabene1111
d702c08a12 fixed urlize breaking markdown links 2020-04-25 10:46:27 +02:00
19 changed files with 580 additions and 197 deletions

View File

@@ -3,6 +3,8 @@ Recipes is a Django application to manage, tag and search recipes using either b
![Preview](docs/preview.png)
[More Screenshots](https://imgur.com/a/V01151p)
### Features
- :package: **Sync** files with Dropbox and Nextcloud (more can easily be added)
@@ -12,13 +14,15 @@ Recipes is a Django application to manage, tag and search recipes using either b
- :iphone: Optimized for use on **mobile** devices like phones and tablets
- :shopping_cart: Generate **shopping** lists from recipes
- :calendar: Create a **Plan** on what to eat when
- :person_with_blond_hair: **Share** recipes with friends and comment on them to suggest or remember changes you made
- :family: **Share** recipes with friends and comment on them to suggest or remember changes you made
- :whale: Easy setup with **Docker**
- :art: Customize your interface with **themes**
- :envelope: Export and import recipes from other users
- :heavy_plus_sign: Many more like recipe scaling, image compression, cookbooks, printing views, ...
This application is meant for people with a collection of recipes they want to share with family and friends or simply store them in a nicely organized way. A basic permission system exists but this application is not meant to be run as a public page.
This application is meant for people with a collection of recipes they want to share with family and friends or simply
store them in a nicely organized way. A basic permission system exists but this application is not meant to be run as a public page.
Some Documentation can be found [here](https://github.com/vabene1111/recipes/wiki)
# Installation
The docker image (`vabene1111/recipes`) simply exposes the application on port `8080`. You may choose any preferred installation method, the following are just examples to make it easier.
@@ -38,7 +42,6 @@ Otherwise simply follow the instructions for any django based deployment
(for example [this one](http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html)).
## Updating
While intermediate updates can be skipped when updating please make sure to **read the release notes** in case some special action is required to update.
0. Before updating it is recommended to **create a backup!**
@@ -50,31 +53,6 @@ While intermediate updates can be skipped when updating please make sure to **re
You can find a basic kubernetes setup [here](docs/k8s/). Please see the README in the folder for more detail.
# Documentation
Most things should be straight forward but there are some more complicated things.
##### Storage Backends
A `Storage Backend` is a remote storage location where PDF files are read from. To add a new backend click on `Storage Data` and then on `Storage Backends`. There click the plus button.
Enter a name (just a display name for you to identify it) and an API access Token for the account you want to use.
Dropboxes API tokens can be found on the [Dropboxes API explorer](https://dropbox.github.io/dropbox-api-v2-explorer/#auth_token/from_oauth1)
with the button on the top right. For Nextcloud you can use a App apssword created in the settings.
##### Adding Synced Paths
To add a new path from your Storage backend to the sync list, go to `Storage Data >> Configure Sync` and select the storage backend you want to use.
Then enter the path you want to monitor starting at the storage root (e.g. `/Folder/RecipesFolder`) and save it.
##### Syncing Data
To sync the recipes app with the storage backends press `Sync now` under `Storage Data >> Configure Sync`.
##### Import Recipes
All files found by the sync can be found under `Manage Data >> Import recipes`. There you can either import all at once without modifying them or import one by one, adding tags while importing.
##### Batch Edit
If you have many untagged recipes, you may want to edit them all at once. To do so, go to
`Storage Data >> Batch Edit`. Enter a word which should be contained in the recipe name and select the tags you want to apply.
When clicking submit, every recipe containing the word will be updated (tags are added).
> Currently the only option is word contains, maybe some more SQL like operators will be added later.
## Contributing
Pull Requests and ideas are welcome, feel free to contribute in any way.
For any questions on how to work with django please refer to their excellent [documentation](https://www.djangoproject.com/start/).

View File

@@ -1,4 +1,3 @@
from dal import autocomplete
from django import forms
from django.forms import widgets
from django.utils.translation import gettext as _
@@ -100,6 +99,25 @@ class ShoppingForm(forms.Form):
)
class ExportForm(forms.Form):
recipe = forms.ModelChoiceField(
queryset=Recipe.objects.filter(internal=True).all(),
widget=SelectWidget
)
image = forms.BooleanField(
help_text=_('Export Base64 encoded image?'),
required=False
)
download = forms.BooleanField(
help_text=_('Download export directly or show on page?'),
required=False
)
class ImportForm(forms.Form):
recipe = forms.CharField(widget=forms.Textarea, help_text=_('Simply paste a JSON export into this textarea and click import.'))
class UnitMergeForm(forms.Form):
prefix = 'unit'

View File

@@ -0,0 +1,81 @@
"""A more liberal autolinker
Inspired by Django's urlize function.
Positive examples:
>>> import markdown
>>> md = markdown.Markdown(extensions=['urlize'])
>>> md.convert('http://example.com/')
u'<p><a href="http://example.com/">http://example.com/</a></p>'
>>> md.convert('go to http://example.com')
u'<p>go to <a href="http://example.com">http://example.com</a></p>'
>>> md.convert('example.com')
u'<p><a href="http://example.com">example.com</a></p>'
>>> md.convert('example.net')
u'<p><a href="http://example.net">example.net</a></p>'
>>> md.convert('www.example.us')
u'<p><a href="http://www.example.us">www.example.us</a></p>'
>>> md.convert('(www.example.us/path/?name=val)')
u'<p>(<a href="http://www.example.us/path/?name=val">www.example.us/path/?name=val</a>)</p>'
>>> md.convert('go to <http://example.com> now!')
u'<p>go to <a href="http://example.com">http://example.com</a> now!</p>'
Negative examples:
>>> md.convert('del.icio.us')
u'<p>del.icio.us</p>'
"""
import markdown
# Global Vars
URLIZE_RE = '(%s)' % '|'.join([
r'<(?:f|ht)tps?://[^>]*>',
r'\b(?:f|ht)tps?://[^)<>\s]+[^.,)<>\s]',
r'\bwww\.[^)<>\s]+[^.,)<>\s]',
r'[^(<\s]+\.(?:com|net|org)\b',
])
class UrlizePattern(markdown.inlinepatterns.Pattern):
""" Return a link Element given an autolink (`http://example/com`). """
def handleMatch(self, m):
url = m.group(2)
if url.startswith('<'):
url = url[1:-1]
text = url
if not url.split('://')[0] in ('http','https','ftp'):
if '@' in url and not '/' in url:
url = 'mailto:' + url
else:
url = 'http://' + url
el = markdown.util.etree.Element("a")
el.set('href', url)
el.text = markdown.util.AtomicString(text)
return el
class UrlizeExtension(markdown.Extension):
""" Urlize Extension for Python-Markdown. """
def extendMarkdown(self, md, md_globals):
""" Replace autolink with UrlizePattern """
md.inlinePatterns['autolink'] = UrlizePattern(URLIZE_RE, md)
def makeExtension(*args, **kwargs):
return UrlizeExtension(*args, **kwargs)
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@@ -7,25 +7,25 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-18 12:13+0100\n"
"PO-Revision-Date: 2020-03-18 12:19+0100\n"
"POT-Creation-Date: 2020-04-25 23:31+0200\n"
"PO-Revision-Date: 2020-04-25 23:31+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 2.3\n"
#: .\cookbook\filters.py:15 .\cookbook\templates\base.html:98
#: .\cookbook\filters.py:15 .\cookbook\templates\base.html:99
#: .\cookbook\templates\forms\edit_internal_recipe.html:28
#: .\cookbook\templates\forms\ingredients.html:34
#: .\cookbook\templates\recipe_view.html:104 .\cookbook\views\lists.py:45
#: .\cookbook\templates\recipe_view.html:110 .\cookbook\views\lists.py:45
msgid "Ingredients"
msgstr "Zutaten"
#: .\cookbook\forms.py:35
#: .\cookbook\forms.py:36
msgid ""
"Color of the top navigation bar. Not all colors work with all themes, just "
"try them out!"
@@ -33,36 +33,48 @@ msgstr ""
"Farbe der oberen Navigationsleiste. Nicht alle Farben passen, daher einfach "
"mal ausprobieren!"
#: .\cookbook\forms.py:49 .\cookbook\forms.py:67 .\cookbook\forms.py:196
#: .\cookbook\forms.py:37
msgid "Default Unit to be used when inserting a new ingredient into a recipe."
msgstr "Standard Einheit für neue Zutaten."
#: .\cookbook\forms.py:49
msgid ""
"Both fields are optional. If none are given the username will be displayed "
"instead"
msgstr ""
"Beide Felder sind optional, wenn keins von beiden gegeben ist wird der "
"Nutzername angezeigt"
#: .\cookbook\forms.py:63 .\cookbook\forms.py:81 .\cookbook\forms.py:229
msgid "Name"
msgstr "Name"
#: .\cookbook\forms.py:50 .\cookbook\forms.py:68 .\cookbook\forms.py:197
#: .\cookbook\forms.py:64 .\cookbook\forms.py:82 .\cookbook\forms.py:230
#: .\cookbook\templates\stats.html:22
msgid "Keywords"
msgstr "Schlagwörter"
#: .\cookbook\forms.py:51 .\cookbook\forms.py:70
#: .\cookbook\forms.py:65 .\cookbook\forms.py:84
msgid "Preparation time in minutes"
msgstr "Zubereitungszeit in Minuten"
#: .\cookbook\forms.py:52 .\cookbook\forms.py:71
#: .\cookbook\forms.py:66 .\cookbook\forms.py:85
msgid "Waiting time (cooking/baking) in minutes"
msgstr "Wartezeit (kochen/backen) in Minuten"
#: .\cookbook\forms.py:53 .\cookbook\forms.py:198
#: .\cookbook\forms.py:67 .\cookbook\forms.py:231
msgid "Path"
msgstr "Pfad"
#: .\cookbook\forms.py:54
#: .\cookbook\forms.py:68
msgid "Storage UID"
msgstr "Speicher ID"
#: .\cookbook\forms.py:69
#: .\cookbook\forms.py:83
msgid "Instructions"
msgstr "Anleitung"
#: .\cookbook\forms.py:82
#: .\cookbook\forms.py:96
msgid ""
"Include <code>- [ ]</code> in list for easier usage in markdown based "
"documents."
@@ -70,51 +82,63 @@ msgstr ""
"Füge <code>- [ ]</code> vor den Zutaten ein um sie besser in einem Markdown "
"Dokument zu verwenden."
#: .\cookbook\forms.py:94
#: .\cookbook\forms.py:108
msgid "Export Base64 encoded image?"
msgstr "Base64 kodiertes Bild exportieren ?"
#: .\cookbook\forms.py:112
msgid "Download export directly or show on page?"
msgstr "Direkter Download oder anzeige auf Seite ?"
#: .\cookbook\forms.py:118
msgid "Simply paste a JSON export into this textarea and click import."
msgstr "Einfach JSON in die Textbox einfügen und importieren klicken."
#: .\cookbook\forms.py:127
msgid "New Unit"
msgstr "Neue Einheit"
#: .\cookbook\forms.py:95
#: .\cookbook\forms.py:128
msgid "New unit that other gets replaced by."
msgstr "Neue Einheit die die alte ersetzt."
#: .\cookbook\forms.py:100
#: .\cookbook\forms.py:133
msgid "Old Unit"
msgstr "Alte Einheit"
#: .\cookbook\forms.py:101
#: .\cookbook\forms.py:134
msgid "Unit that should be replaced."
msgstr "Einheit die ersetzt werden soll."
#: .\cookbook\forms.py:111
#: .\cookbook\forms.py:144
msgid "New Ingredient"
msgstr "Neue Zutat"
#: .\cookbook\forms.py:112
#: .\cookbook\forms.py:145
msgid "New ingredient that other gets replaced by."
msgstr "Neue Zutat die die alte ersetzt."
#: .\cookbook\forms.py:117
#: .\cookbook\forms.py:150
msgid "Old Ingredient"
msgstr "Alte Zutat"
#: .\cookbook\forms.py:118
#: .\cookbook\forms.py:151
msgid "Ingredient that should be replaced."
msgstr "Zutat die ersetzt werden soll."
#: .\cookbook\forms.py:130
#: .\cookbook\forms.py:163
msgid "Add your comment: "
msgstr "Schreibe einen Kommentar:"
msgstr "Schreibe einen Kommentar: "
#: .\cookbook\forms.py:155
#: .\cookbook\forms.py:188
msgid "Leave empty for dropbox and enter app password for nextcloud."
msgstr "Für Dropbox leer lassen, bei Nextcloud App-Passwort eingeben."
#: .\cookbook\forms.py:158
#: .\cookbook\forms.py:191
msgid "Leave empty for nextcloud and enter api token for dropbox."
msgstr "Bei Nextcloud leer lassen, bei Dropbox API Token eingeben."
#: .\cookbook\forms.py:166
#: .\cookbook\forms.py:199
msgid ""
"Leave empty for dropbox and enter only base url for nextcloud (<code>/remote."
"php/webdav/</code> is added automatically)"
@@ -122,119 +146,128 @@ msgstr ""
"Bei Dropbox leer lassen, bei Nextcloud Server URL angeben (<code>/remote.php/"
"webdav/</code> wird automatisch hinzugefügt)"
#: .\cookbook\forms.py:185
#: .\cookbook\forms.py:218
msgid "Search String"
msgstr "Such Wort"
#: .\cookbook\forms.py:199
#: .\cookbook\forms.py:232
msgid "File ID"
msgstr "Datei ID"
#: .\cookbook\models.py:190
#: .\cookbook\models.py:49
msgid "Search"
msgstr "Suche"
#: .\cookbook\models.py:49 .\cookbook\templates\base.html:93
#: .\cookbook\templates\meal_plan.html:4 .\cookbook\templates\meal_plan.html:32
#: .\cookbook\views\delete.py:136 .\cookbook\views\edit.py:286
#: .\cookbook\views\new.py:138
msgid "Meal-Plan"
msgstr "Plan"
#: .\cookbook\models.py:49 .\cookbook\templates\base.html:90
msgid "Books"
msgstr "Bücher"
#: .\cookbook\models.py:210
msgid "Breakfast"
msgstr "Frühstück"
#: .\cookbook\models.py:190
#: .\cookbook\models.py:210
msgid "Lunch"
msgstr "Mittagessen"
#: .\cookbook\models.py:190
#: .\cookbook\models.py:210
msgid "Dinner"
msgstr "Abendessen"
#: .\cookbook\models.py:190
#: .\cookbook\models.py:210
msgid "Other"
msgstr "Andere"
#: .\cookbook\tables.py:83
#: .\cookbook\templates\forms\edit_internal_recipe.html:49
#: .\cookbook\templates\forms\edit_internal_recipe.html:160
#: .\cookbook\templates\forms\edit_internal_recipe.html:50
#: .\cookbook\templates\forms\edit_internal_recipe.html:161
#: .\cookbook\templates\generic\delete_template.html:5
#: .\cookbook\templates\generic\delete_template.html:13
#: .\cookbook\templates\generic\edit_template.html:25
msgid "Delete"
msgstr "Löschen"
#: .\cookbook\templates\base.html:70 .\cookbook\templates\base.html:78
#: .\cookbook\templates\base.html:70 .\cookbook\templates\base.html:79
#: .\cookbook\templates\forms\ingredients.html:7
#: .\cookbook\templates\index.html:7 .\cookbook\templates\shopping_list.html:7
msgid "Cookbook"
msgstr "Kochbuch"
#: .\cookbook\templates\base.html:85
#: .\cookbook\templates\base.html:86
msgid "Utensils"
msgstr "Utensilien"
#: .\cookbook\templates\base.html:89
msgid "Books"
msgstr "Bücher"
#: .\cookbook\templates\base.html:92 .\cookbook\templates\meal_plan.html:4
#: .\cookbook\templates\meal_plan.html:13 .\cookbook\views\delete.py:136
#: .\cookbook\views\edit.py:283 .\cookbook\views\new.py:130
msgid "Meal-Plan"
msgstr "Plan"
#: .\cookbook\templates\base.html:95
#: .\cookbook\templates\base.html:96
msgid "Shopping"
msgstr "Einkaufsliste"
#: .\cookbook\templates\base.html:105
#: .\cookbook\templates\base.html:106
msgid "Tags"
msgstr "Schlagwörter"
#: .\cookbook\templates\base.html:109 .\cookbook\views\delete.py:70
#: .\cookbook\views\edit.py:159 .\cookbook\views\lists.py:18
#: .\cookbook\views\new.py:46
#: .\cookbook\templates\base.html:110 .\cookbook\views\delete.py:70
#: .\cookbook\views\edit.py:162 .\cookbook\views\lists.py:18
#: .\cookbook\views\new.py:47
msgid "Keyword"
msgstr "Schlagwort"
#: .\cookbook\templates\base.html:111
#: .\cookbook\templates\base.html:112
msgid "Batch Edit"
msgstr "Massenbearbeitung"
#: .\cookbook\templates\base.html:116
#: .\cookbook\templates\base.html:117
msgid "Storage Data"
msgstr "Datenquellen"
#: .\cookbook\templates\base.html:120
#: .\cookbook\templates\base.html:121
msgid "Storage Backends"
msgstr "Speicher Quellen"
#: .\cookbook\templates\base.html:122
#: .\cookbook\templates\base.html:123
msgid "Configure Sync"
msgstr "Sync Einstellen"
#: .\cookbook\templates\base.html:124
msgid "Import Recipes"
msgstr "Importierte Rezepte"
#: .\cookbook\templates\base.html:125
msgid "Discovered Recipes"
msgstr "Entdeckte Rezepte"
#: .\cookbook\templates\base.html:126 .\cookbook\views\lists.py:26
msgid "Import Log"
msgstr "Import Log"
#: .\cookbook\templates\base.html:127
msgid "Discovery Log"
msgstr "Entdeckungs Log"
#: .\cookbook\templates\base.html:128 .\cookbook\templates\stats.html:10
#: .\cookbook\templates\base.html:129 .\cookbook\templates\stats.html:10
msgid "Statistics"
msgstr "Statistiken"
#: .\cookbook\templates\base.html:130
#: .\cookbook\templates\base.html:131
msgid "Units & Ingredients"
msgstr "Einheiten & Zutaten"
#: .\cookbook\templates\base.html:145 .\cookbook\templates\settings.html:6
#: .\cookbook\templates\base.html:133
msgid "Import Recipe"
msgstr "Importier Rezept"
#: .\cookbook\templates\base.html:149 .\cookbook\templates\settings.html:6
#: .\cookbook\templates\settings.html:11
msgid "Settings"
msgstr "Einstellungen"
#: .\cookbook\templates\base.html:148
#: .\cookbook\templates\base.html:152
msgid "Admin"
msgstr "Admin"
#: .\cookbook\templates\base.html:152
#: .\cookbook\templates\base.html:156
msgid "Logout"
msgstr "Ausloggen"
#: .\cookbook\templates\base.html:157
#: .\cookbook\templates\base.html:161
#: .\cookbook\templates\registration\login.html:44
msgid "Login"
msgstr "Einloggen"
@@ -253,7 +286,7 @@ msgstr ""
"Ausgewählte Schlagwörter zu allen Rezepten die das Suchwort enthalten "
"hinzufügen"
#: .\cookbook\templates\batch\monitor.html:6 .\cookbook\views\edit.py:143
#: .\cookbook\templates\batch\monitor.html:6 .\cookbook\views\edit.py:146
msgid "Sync"
msgstr "Synchronisieren"
@@ -302,17 +335,45 @@ msgstr "Neues Buch"
msgid "There are no recipes in this book yet."
msgstr "In diesem Buch sind bisher keine Rezepte."
#: .\cookbook\templates\export.html:6
msgid "Export Recipes"
msgstr "Exportier Rezepte"
#: .\cookbook\templates\export.html:19
msgid "Export"
msgstr "Export"
#: .\cookbook\templates\export.html:31
msgid "Exported Recipe"
msgstr "Exportierte Rezepte"
#: .\cookbook\templates\export.html:42
msgid "Copy to clipboard"
msgstr "In Zwischenablage kopieren"
#: .\cookbook\templates\export.html:54
#: .\cookbook\templates\shopping_list.html:48
msgid "Copied!"
msgstr "Kopiert!"
#: .\cookbook\templates\export.html:61
#: .\cookbook\templates\shopping_list.html:37
#: .\cookbook\templates\shopping_list.html:55
msgid "Copy list to clipboard"
msgstr "Kopiere Liste in Zwischenablage"
#: .\cookbook\templates\forms\edit_import_recipe.html:5
#: .\cookbook\templates\forms\edit_import_recipe.html:9
msgid "Import new Recipe"
msgstr "Rezept Importieren"
#: .\cookbook\templates\forms\edit_import_recipe.html:14
#: .\cookbook\templates\forms\edit_internal_recipe.html:47
#: .\cookbook\templates\forms\edit_internal_recipe.html:48
#: .\cookbook\templates\generic\edit_template.html:23
#: .\cookbook\templates\generic\new_template.html:23
#: .\cookbook\templates\recipe_view.html:340
#: .\cookbook\templates\settings.html:33 .\cookbook\templates\settings.html:47
#: .\cookbook\templates\recipe_view.html:357
#: .\cookbook\templates\settings.html:22 .\cookbook\templates\settings.html:28
#: .\cookbook\templates\settings.html:50 .\cookbook\templates\settings.html:64
msgid "Save"
msgstr "Speichern"
@@ -321,7 +382,7 @@ msgstr "Speichern"
msgid "Edit Recipe"
msgstr "Rezept bearbeiten"
#: .\cookbook\templates\forms\edit_internal_recipe.html:37
#: .\cookbook\templates\forms\edit_internal_recipe.html:38
msgid ""
"Use <b>Ctrl</b>+<b>Space</b> to insert new Ingredient!<br/>You can also save "
"the recipe using <b>Ctrl</b>+<b>Shift</b>+<b>S</b>."
@@ -329,36 +390,35 @@ msgstr ""
"Benutze <b>Strg</b>+<b>Leertaste</b> um eine neue Zutat einzufügen!<br/"
">Rezepte können mit<b>Strg</b>+<b>Shift</b>+<b>S</b> gespeichert werden."
#: .\cookbook\templates\forms\edit_internal_recipe.html:51
#: .\cookbook\templates\forms\edit_internal_recipe.html:52
#: .\cookbook\templates\generic\edit_template.html:27
#: .\cookbook\templates\recipe_view.html:7
msgid "View"
msgstr "Angucken"
#: .\cookbook\templates\forms\edit_internal_recipe.html:55
#: .\cookbook\templates\forms\edit_internal_recipe.html:56
#: .\cookbook\templates\generic\edit_template.html:30
msgid "Delete original file"
msgstr "Original löschen"
#: .\cookbook\templates\forms\edit_internal_recipe.html:142
#: .\cookbook\templates\forms\edit_internal_recipe.html:189
#: .\cookbook\views\delete.py:81 .\cookbook\views\edit.py:175
#: .\cookbook\templates\forms\edit_internal_recipe.html:143
#: .\cookbook\templates\forms\edit_internal_recipe.html:190
#: .\cookbook\views\delete.py:81 .\cookbook\views\edit.py:178
msgid "Ingredient"
msgstr "Zutat"
#: .\cookbook\templates\forms\edit_internal_recipe.html:147
#: .\cookbook\templates\forms\edit_internal_recipe.html:148
msgid "Amount"
msgstr "Menge"
#: .\cookbook\templates\forms\edit_internal_recipe.html:149
#: .\cookbook\templates\forms\edit_internal_recipe.html:150
msgid "Unit"
msgstr "Einheit"
#: .\cookbook\templates\forms\edit_internal_recipe.html:154
#: .\cookbook\templates\forms\edit_internal_recipe.html:155
msgid "Note"
msgstr "Notiz "
msgstr "Notiz"
#: .\cookbook\templates\forms\edit_internal_recipe.html:163
#: .\cookbook\templates\forms\edit_internal_recipe.html:164
msgid "Are you sure that you want to delete this ingredient?"
msgstr "Bist du sicher das du diese Zutat löschen willst?"
@@ -404,7 +464,7 @@ msgstr "Bist du sicher diese beiden Zutaten zusammengeführt werden sollen ?"
#: .\cookbook\templates\generic\delete_template.html:18
#, python-format
msgid "Are you sure you want to delete the %(title)s: <b>%(object)s</b> "
msgstr "Bist du sicher das %(title)s: <b>%(object)s</b> gelöscht werden soll"
msgstr "Bist du sicher das %(title)s: <b>%(object)s</b> gelöscht werden soll "
#: .\cookbook\templates\generic\delete_template.html:21
msgid "Confirm"
@@ -441,9 +501,18 @@ msgstr "vorherige"
msgid "next"
msgstr "nächste"
#: .\cookbook\templates\import.html:6
msgid "Import Recipes"
msgstr "Importierte Rezepte"
#: .\cookbook\templates\import.html:14 .\cookbook\views\delete.py:48
#: .\cookbook\views\edit.py:254
msgid "Import"
msgstr "Rezept Importieren"
#: .\cookbook\templates\include\recipe_open_modal.html:28
#: .\cookbook\views\delete.py:21 .\cookbook\views\edit.py:315
#: .\cookbook\views\new.py:34
#: .\cookbook\views\delete.py:21 .\cookbook\views\edit.py:318
#: .\cookbook\views\new.py:35
msgid "Recipe"
msgstr "Rezept"
@@ -501,47 +570,47 @@ msgstr "Suche zurücksetzen"
msgid "Log in to view Recipies"
msgstr "Bitte einloggen um Rezepte zu sehen"
#: .\cookbook\templates\meal_plan.html:20
#: .\cookbook\templates\meal_plan.html:39
msgid "Week"
msgstr "Woche"
#: .\cookbook\templates\recipe_view.html:67
#: .\cookbook\templates\recipe_view.html:71
msgid "in"
msgstr "in"
#: .\cookbook\templates\recipe_view.html:72
#: .\cookbook\templates\recipe_view.html:293
#: .\cookbook\templates\recipe_view.html:76
#: .\cookbook\templates\recipe_view.html:310
msgid "by"
msgstr "von"
#: .\cookbook\templates\recipe_view.html:84
#: .\cookbook\templates\recipe_view.html:89
msgid "Preparation time ca."
msgstr "Zubereitungszeit ca."
#: .\cookbook\templates\recipe_view.html:89
#: .\cookbook\templates\recipe_view.html:95
msgid "Waiting time ca."
msgstr "Wartezeit ca."
#: .\cookbook\templates\recipe_view.html:170
#: .\cookbook\templates\recipe_view.html:186
msgid "Recipe Image"
msgstr "Rezept Bild"
#: .\cookbook\templates\recipe_view.html:193
#: .\cookbook\templates\recipe_view.html:227
#: .\cookbook\templates\recipe_view.html:209
#: .\cookbook\templates\recipe_view.html:243
msgid "View external recipe"
msgstr "Externes Rezept ansehen"
#: .\cookbook\templates\recipe_view.html:205
#: .\cookbook\templates\recipe_view.html:221
msgid "Cloud not show a file preview. Maybe its not a PDF ?"
msgstr ""
"Datei konnte nicht angezeigt werden. Direkte anzeige funktioniert nur mit "
"PDF Dateien."
#: .\cookbook\templates\recipe_view.html:212
#: .\cookbook\templates\recipe_view.html:228
msgid "External recipe"
msgstr "Externes Rezept"
#: .\cookbook\templates\recipe_view.html:214
#: .\cookbook\templates\recipe_view.html:230
msgid ""
"\n"
" This is an external recipe, which means "
@@ -562,16 +631,16 @@ msgstr ""
"bleibt weiterhin verfügbar.\n"
" "
#: .\cookbook\templates\recipe_view.html:225
#: .\cookbook\templates\recipe_view.html:241
msgid "Convert now!"
msgstr "Jetzt umwandeln!"
#: .\cookbook\templates\recipe_view.html:289
#: .\cookbook\templates\recipe_view.html:305
msgid "Comments"
msgstr "Kommentare"
#: .\cookbook\templates\recipe_view.html:309 .\cookbook\views\delete.py:103
#: .\cookbook\views\edit.py:234
#: .\cookbook\templates\recipe_view.html:326 .\cookbook\views\delete.py:103
#: .\cookbook\views\edit.py:237
msgid "Comment"
msgstr "Kommentar"
@@ -580,10 +649,14 @@ msgid "Your username and password didn't match. Please try again."
msgstr "Nutzername oder Passwort falsch. Bitte versuch es erneut."
#: .\cookbook\templates\settings.html:17
msgid "Account"
msgstr "Account"
#: .\cookbook\templates\settings.html:34
msgid "Language"
msgstr "Sprache"
#: .\cookbook\templates\settings.html:42
#: .\cookbook\templates\settings.html:59
msgid "Style"
msgstr "Stil"
@@ -595,15 +668,6 @@ msgstr "Einkaufsliste"
msgid "Load"
msgstr "Laden"
#: .\cookbook\templates\shopping_list.html:37
#: .\cookbook\templates\shopping_list.html:55
msgid "Copy list to clipboard"
msgstr "Kopiere Liste in Zwischenablage"
#: .\cookbook\templates\shopping_list.html:48
msgid "Copied!"
msgstr "Kopiert!"
#: .\cookbook\templates\stats.html:4
msgid "Stats"
msgstr "Statistiken"
@@ -644,22 +708,17 @@ msgstr[0] "Massenbearbeitung erfolgreich. %(count)d Rezept wurde aktualisiert."
msgstr[1] ""
"Massenbearbeitung erfolgreich. %(count)d Rezepte wurden aktualisiert."
#: .\cookbook\views\delete.py:48 .\cookbook\views\edit.py:251
#: .\cookbook\views\lists.py:35
msgid "Import"
msgstr "Rezept Importieren"
#: .\cookbook\views\delete.py:59
msgid "Monitor"
msgstr "Monitor"
#: .\cookbook\views\delete.py:92 .\cookbook\views\lists.py:53
#: .\cookbook\views\new.py:64
#: .\cookbook\views\new.py:65
msgid "Storage Backend"
msgstr "Speicher Quelle"
#: .\cookbook\views\delete.py:114 .\cookbook\views\edit.py:267
#: .\cookbook\views\new.py:112
#: .\cookbook\views\delete.py:114 .\cookbook\views\edit.py:270
#: .\cookbook\views\new.py:114
msgid "Recipe Book"
msgstr "Rezeptbuch"
@@ -667,58 +726,82 @@ msgstr "Rezeptbuch"
msgid "Bookmarks"
msgstr "Lesezeichen"
#: .\cookbook\views\edit.py:117
#: .\cookbook\views\edit.py:104
msgid "There was an error converting your ingredients amount to a number: "
msgstr "Es gab einen Fehler beim umwandeln der Menge in eine Zahl: "
#: .\cookbook\views\edit.py:120
msgid "Recipe saved!"
msgstr "Rezept gespeichert"
msgstr "Rezept gespeichert!"
#: .\cookbook\views\edit.py:119
#: .\cookbook\views\edit.py:122
msgid "There was an error saving this recipe!"
msgstr "Es gab einen Fehler beim Speichern des Rezepts"
msgstr "Es gab einen Fehler beim Speichern des Rezepts!"
#: .\cookbook\views\edit.py:184
#: .\cookbook\views\edit.py:187
msgid "You cannot edit this storage!"
msgstr "Du kannst diese Speicherquelle nicht bearbeiten!"
#: .\cookbook\views\edit.py:203
#: .\cookbook\views\edit.py:206
msgid "Storage saved!"
msgstr "Speicherquelle gespeichert"
msgstr "Speicherquelle gespeichert!"
#: .\cookbook\views\edit.py:205
msgid "There was an error updating this storage backend.!"
msgstr "Es gab einen Fehler beim aktualisierung dieser Speicher Quelle"
#: .\cookbook\views\edit.py:208
msgid "There was an error updating this storage backend!"
msgstr "Es gab einen Fehler beim aktualisierung dieser Speicher Quelle!"
#: .\cookbook\views\edit.py:225
#: .\cookbook\views\edit.py:228
msgid "You cannot edit this comment!"
msgstr "Du kannst diesen Kommentar nicht bearbeiten!"
#: .\cookbook\views\edit.py:303
#: .\cookbook\views\edit.py:306
msgid "Changes saved!"
msgstr "Änderungen gespeichert"
msgstr "Änderungen gespeichert!"
#: .\cookbook\views\edit.py:307
#: .\cookbook\views\edit.py:310
msgid "Error saving changes!"
msgstr "Fehler beim Speichern der Daten."
msgstr "Fehler beim Speichern der Daten!"
#: .\cookbook\views\edit.py:337
#: .\cookbook\views\edit.py:340
msgid "Units merged!"
msgstr "Einheiten zusammengeführt"
msgstr "Einheiten zusammengeführt!"
#: .\cookbook\views\edit.py:350
#: .\cookbook\views\edit.py:353
msgid "Ingredients merged!"
msgstr "Zutaten zusammengeführt"
msgstr "Zutaten zusammengeführt!"
#: .\cookbook\views\new.py:86
#: .\cookbook\views\import_export.py:57
msgid "Recipe imported successfully!"
msgstr "Rezept erfolgreich importiert!"
#: .\cookbook\views\import_export.py:103
msgid ""
"External recipes cannot be exported, please share the file directly or "
"select an internal recipe."
msgstr ""
"Externe Rezepte können nicht exportiert werden, bitte Datei direkt teilen "
"oder ein Internes Rezept auswählen."
#: .\cookbook\views\lists.py:26
msgid "Import Log"
msgstr "Import Log"
#: .\cookbook\views\lists.py:35
msgid "Discovery"
msgstr "Entdeckung"
#: .\cookbook\views\new.py:88
msgid "Imported new recipe!"
msgstr "Importier neue Rezepte"
msgstr "Importier neue Rezepte!"
#: .\cookbook\views\new.py:89
#: .\cookbook\views\new.py:91
msgid "There was an error importing this recipe!"
msgstr "Beim importieren des Rezeptes ist ein Fehler aufgetreten"
msgstr "Beim importieren des Rezeptes ist ein Fehler aufgetreten!"
#: .\cookbook\views\views.py:44
#: .\cookbook\views\views.py:63
msgid "Comment saved!"
msgstr "Kommentar gespeichert"
msgstr "Kommentar gespeichert!"
#: .\cookbook\views\views.py:54
#: .\cookbook\views\views.py:73
msgid "Bookmark saved!"
msgstr "Lesezeichen gespeichert"
msgstr "Lesezeichen gespeichert!"

View File

@@ -154,8 +154,8 @@ class Ingredient(models.Model):
class RecipeIngredient(models.Model):
ingredient = models.ForeignKey(Ingredient, on_delete=models.PROTECT)
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, on_delete=models.PROTECT)
unit = models.ForeignKey(Unit, on_delete=models.PROTECT)
amount = models.DecimalField(default=0, decimal_places=2, max_digits=16)
note = models.CharField(max_length=64, null=True, blank=True)

View File

@@ -75,7 +75,8 @@
<div class="collapse navbar-collapse" id="navbarText">
<ul class="navbar-nav mr-auto">
<li class="nav-item {% if request.resolver_match.url_name in 'view_search,edit_recipe,edit_internal_recipe,edit_external_recipe,view_recipe' %}active{% endif %}">
<a class="nav-link" href="{% url 'view_search' %}"><i class="fas fa-book"></i> {% trans 'Cookbook' %}<span
<a class="nav-link" href="{% url 'view_search' %}"><i
class="fas fa-book"></i> {% trans 'Cookbook' %}<span
class="sr-only">(current)</span></a>
</li>
@@ -121,13 +122,15 @@
<a class="dropdown-item" href="{% url 'data_sync' %}"><i
class="fas fa-sync-alt fa-fw"></i> {% trans 'Configure Sync' %}</a>
<a class="dropdown-item" href="{% url 'list_recipe_import' %}"><i
class="far fa-file-alt fa-fw"></i> {% trans 'Import Recipes' %}</a>
class="far fa-file-alt fa-fw"></i> {% trans 'Discovered Recipes' %}</a>
<a class="dropdown-item" href="{% url 'list_sync_log' %}"><i
class="fas fa-history fa-fw"></i> {% trans 'Import Log' %}</a>
class="fas fa-history fa-fw"></i> {% trans 'Discovery Log' %}</a>
<a class="dropdown-item" href="{% url 'data_stats' %}"><i
class="fas fa-chart-line fa-fw"></i> {% trans 'Statistics' %}</a>
<a class="dropdown-item" href="{% url 'edit_ingredient' %}"><i
class="fas fa-balance-scale fa-fw"></i> {% trans 'Units & Ingredients' %}</a>
<a class="dropdown-item" href="{% url 'view_import' %}"><i
class="fas fa-file-import"></i> {% trans 'Import Recipe' %}</a>
</div>
</li>
@@ -137,7 +140,8 @@
{% if user.is_authenticated %}
<li class="nav-item dropdown {% if request.resolver_match.url_name in 'view_settings' %}active{% endif %}">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false"><i class="fas fa-user-alt"></i> {{ user.get_user_name }}
aria-haspopup="true" aria-expanded="false"><i
class="fas fa-user-alt"></i> {{ user.get_user_name }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">

View File

@@ -0,0 +1,70 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% load static %}
{% block title %}{% trans 'Export Recipes' %}{% endblock %}
{% block extra_head %}
{{ form.media }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col col-md-12">
<form action="." method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit"><i class="fas fa-file-export"></i> {% trans 'Export' %}
</button>
</form>
</div>
</div>
{% if export %}
<br/>
<div class="row">
<div class="col col-md-12">
<label for="id_export">
{% trans 'Exported Recipe' %}</label>
<textarea id="id_export" class="form-control" rows="12">
{{ export }}
</textarea>
</div>
</div>
<br/>
<div class="row">
<div class="col col-md-12 text-center">
<button class="btn btn-success" onclick="copy()" style="width: 15vw" data-toggle="tooltip"
data-placement="right" title="{% trans 'Copy to clipboard' %}" id="id_btn_copy"
onmouseout="resetTooltip()"><i
class="far fa-copy"></i></button>
</div>
</div>
<script type="text/javascript">
function copy() {
let json = $('#id_export');
json.select();
$('#id_btn_copy').attr('data-original-title', '{% trans 'Copied!' %}').tooltip('show');
document.execCommand("copy");
}
function resetTooltip() {
setTimeout(function () {
$('#id_btn_copy').attr('data-original-title', '{% trans 'Copy list to clipboard' %}');
}, 300);
}
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,19 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load static %}
{% block title %}{% trans 'Import Recipes' %}{% endblock %}
{% block content %}
<div class="row">
<div class="col col-md-12">
<form action="." method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit"><i class="fas fa-file-import"></i> {% trans 'Import' %}
</button>
</form>
</div>
</div>
{% endblock %}

View File

@@ -52,16 +52,24 @@
class="fas fa-pencil-alt"></i></a></h3>
</div>
<div class="col col-md-3 d-print-none" style="text-align: right">
<button class="btn btn-success" onclick="$('#bookmarkModal').modal({'show':true})"><i
<button class="btn btn-success" onclick="$('#bookmarkModal').modal({'show':true})" data-toggle="tooltip"
data-placement="top" title="{% trans 'Add to Book' %}"><i
class="fas fa-bookmark"></i></button>
{% if ingredients %}
<a class="btn btn-warning" href="{% url 'view_shopping' %}?r={{ recipe.pk }}"><i
<a class="btn btn-warning" href="{% url 'view_shopping' %}?r={{ recipe.pk }}" data-toggle="tooltip"
data-placement="top" title="{% trans 'Generate shopping list' %}"><i
class="fas fa-shopping-cart"></i></a>
{% endif %}
<a class="btn btn-info" href="{% url 'new_meal_plan' %}?recipe={{ recipe.pk }}"><i
<a class="btn btn-info" href="{% url 'new_meal_plan' %}?recipe={{ recipe.pk }}" data-toggle="tooltip"
data-placement="top" title="{% trans 'Add to Mealplan' %}"><i
class="fas fa-calendar"></i></a>
<a class="btn btn-light" onclick="window.print()"><i
<a class="btn btn-light" onclick="window.print()" data-toggle="tooltip"
data-placement="top" title="{% trans 'Print' %}"><i
class="fas fa-print"></i></a>
<a class="btn btn-primary" href="{% url 'view_export' %}?r={{ recipe.pk }}" target="_blank"
data-toggle="tooltip"
data-placement="top" title="{% trans 'Export recipe' %}"><i
class="fas fa-file-export"></i></a>
</div>
</div>
@@ -194,7 +202,7 @@
<div style="font-size: large">
{% if recipe.instructions %}
{{ recipe.instructions | markdown | safe | urlize }}
{{ recipe.instructions | markdown | safe }}
{% endif %}
</div>
@@ -382,5 +390,9 @@
}
}
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
{% endblock %}

View File

@@ -34,7 +34,7 @@
<div class="row">
<div class="col col-md-12 text-center">
<button class="btn btn-success" onclick="copy()" style="width: 15vw" data-toggle="tooltip"
data-placement="top" title="{% trans 'Copy list to clipboard' %}" id="id_btn_copy" onmouseout="resetTooltip()"><i
data-placement="right" title="{% trans 'Copy list to clipboard' %}" id="id_btn_copy" onmouseout="resetTooltip()"><i
class="far fa-copy"></i></button>
</div>
</div>

View File

@@ -5,6 +5,7 @@ from bleach_whitelist import markdown_tags, markdown_attrs, all_styles, print_at
from django.urls import reverse
from cookbook.helper.mdx_attributes import MarkdownFormatExtension
from cookbook.helper.mdx_urlize import UrlizeExtension
from cookbook.models import get_model_name
register = template.Library()
@@ -28,5 +29,5 @@ def delete_url(model, pk):
@register.filter()
def markdown(value):
tags = markdown_tags + ['pre', 'table', 'td', 'tr', 'th', 'tbody', 'style', 'thead']
parsed_md = md.markdown(value, extensions=['markdown.extensions.fenced_code', 'tables', MarkdownFormatExtension()])
parsed_md = md.markdown(value, extensions=['markdown.extensions.fenced_code', 'tables', UrlizeExtension(), MarkdownFormatExtension()])
return bleach.clean(parsed_md, tags, markdown_attrs)

View File

@@ -3,7 +3,7 @@ from pydoc import locate
from django.urls import path
from .views import *
from cookbook.views import api
from cookbook.views import api, import_export
from cookbook.helper import dal
urlpatterns = [
@@ -14,6 +14,9 @@ urlpatterns = [
path('shopping/', views.shopping_list, name='view_shopping'),
path('settings/', views.settings, name='view_settings'),
path('import/', import_export.import_recipe, name='view_import'),
path('export/', import_export.export_recipe, name='view_export'),
path('view/recipe/<int:pk>', views.recipe_view, name='view_recipe'),
path('new/recipe_import/<int:import_id>/', new.create_new_external_recipe, name='new_recipe_import'),

View File

@@ -205,7 +205,7 @@ def edit_storage(request, pk):
messages.add_message(request, messages.SUCCESS, _('Storage saved!'))
else:
messages.add_message(request, messages.ERROR, _('There was an error updating this storage backend.!'))
messages.add_message(request, messages.ERROR, _('There was an error updating this storage backend!'))
else:
pseudo_instance = instance
pseudo_instance.password = '__NO__CHANGE__'

View File

@@ -0,0 +1,114 @@
import base64
import json
import re
from django.contrib import messages
from django.core.files.base import ContentFile
from django.db import IntegrityError
from django.http import HttpResponseRedirect, JsonResponse, HttpResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from cookbook.forms import ExportForm, ImportForm
from cookbook.models import RecipeIngredient, Recipe, Unit, Ingredient, Keyword
def import_recipe(request):
if request.method == "POST":
form = ImportForm(request.POST)
if form.is_valid():
data = json.loads(form.cleaned_data['recipe'])
recipe = Recipe.objects.create(name=data['recipe']['name'], instructions=data['recipe']['instructions'],
working_time=data['recipe']['working_time'], waiting_time=data['recipe']['waiting_time'],
created_by=request.user, internal=True)
for k in data['keywords']:
try:
Keyword.objects.create(name=k['name'], icon=k['icon'], description=k['description']).save()
except IntegrityError:
pass
recipe.keywords.add(Keyword.objects.get(name=k['name']))
for u in data['units']:
try:
Unit.objects.create(name=u['name'], description=u['description']).save()
except IntegrityError:
pass
for i in data['ingredients']:
try:
Ingredient.objects.create(name=i['name']).save()
except IntegrityError:
pass
for ri in data['recipe_ingredients']:
RecipeIngredient.objects.create(recipe=recipe, ingredient=Ingredient.objects.get(name=ri['ingredient']),
unit=Unit.objects.get(name=ri['unit']), amount=ri['amount'], note=ri['note'])
if data['image']:
fmt, img = data['image'].split(';base64,')
ext = fmt.split('/')[-1]
recipe.image = ContentFile(base64.b64decode(img), name=f'{recipe.pk}.{ext}')
recipe.save()
messages.add_message(request, messages.SUCCESS, _('Recipe imported successfully!'))
return HttpResponseRedirect(reverse_lazy('view_recipe', args=[recipe.pk]))
else:
form = ImportForm()
return render(request, 'import.html', {'form': form})
def export_recipe(request):
context = {}
if request.method == "POST":
form = ExportForm(request.POST)
if form.is_valid():
recipe = form.cleaned_data['recipe']
if recipe.internal:
export = {
'recipe': {'name': recipe.name, 'instructions': recipe.instructions, 'working_time': recipe.working_time, 'waiting_time': recipe.working_time},
'units': [],
'ingredients': [],
'recipe_ingredients': [],
'keywords': [],
'image': None
}
for k in recipe.keywords.all():
export['keywords'].append({'name': k.name, 'icon': k.icon, 'description': k.description})
for ri in RecipeIngredient.objects.filter(recipe=recipe).all():
if ri.unit not in export['units']:
export['units'].append({'name': ri.unit.name, 'description': ri.unit.description})
if ri.ingredient not in export['ingredients']:
export['ingredients'].append({'name': ri.ingredient.name})
export['recipe_ingredients'].append({'ingredient': ri.ingredient.name, 'unit': ri.unit.name, 'amount': float(ri.amount), 'note': ri.note})
if recipe.image and form.cleaned_data['image']:
with open(recipe.image.path, 'rb') as img_f:
export['image'] = f'data:image/png;base64,{base64.b64encode(img_f.read()).decode("utf-8")}'
if form.cleaned_data['download']:
response = HttpResponse(json.dumps(export), content_type='text/plain')
response['Content-Disposition'] = f'attachment; filename={recipe.name}.json'
return response
context['export'] = json.dumps(export, indent=4)
else:
form.add_error('recipe', _('External recipes cannot be exported, please share the file directly or select an internal recipe.'))
else:
form = ExportForm()
recipe = request.GET.get('r')
if recipe:
if re.match(r'^([0-9])+$', recipe):
if recipe := Recipe.objects.filter(pk=int(recipe)).first():
form = ExportForm(initial={'recipe': recipe})
context['form'] = form
return render(request, 'export.html', context)

View File

@@ -32,7 +32,7 @@ def recipe_import(request):
RequestConfig(request, paginate={'per_page': 25}).configure(table)
return render(request, 'generic/list_template.html', {'title': _("Import"), 'table': table, 'import_btn': True})
return render(request, 'generic/list_template.html', {'title': _("Discovery"), 'table': table, 'import_btn': True})
@login_required

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-03-18 12:13+0100\n"
"POT-Creation-Date: 2020-04-25 23:31+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,10 +18,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: .\recipes\settings.py:136
#: .\recipes\settings.py:137
msgid "German"
msgstr "Deutsch"
#: .\recipes\settings.py:137
#: .\recipes\settings.py:138
msgid "English"
msgstr "Englisch"