Compare commits

...

506 Commits
1.1.3 ... 1.3.2

Author SHA1 Message Date
vabene1111
1cb37fe2d2 dont allow space manage page in demo 2022-07-13 10:25:22 +02:00
vabene1111
61a9f0647b added userspace admin 2022-07-13 10:24:12 +02:00
vabene1111
0068c75e31 Merge branch 'develop' 2022-07-12 19:41:50 +02:00
vabene1111
5de7fa9d48 fixed another social auth issues 2022-07-12 19:41:46 +02:00
vabene1111
3dc3592783 Merge branch 'develop' 2022-07-12 19:20:42 +02:00
vabene1111
43a082a51a updated translations 2022-07-12 19:20:35 +02:00
vabene1111
4c264673df fixed copy me that importer 2022-07-12 19:20:05 +02:00
vabene1111
d537d73c6a Merge pull request #1930 from Mikhail5555/patch-1
Add documentation for migrating from sqlite3 database to postgresql (Unraid)
2022-07-12 14:46:00 +02:00
vabene1111
5c227ecc57 Merge pull request #1931 from smilerz/fix_cookbookapp_import
updated cookbookapp importer to handle multi-step recipes
2022-07-12 08:45:17 +02:00
smilerz
b03fa4fdf2 updated cookbookapp importer to handle multi-step recipes 2022-07-11 17:21:56 -05:00
vabene1111
38219a22ca fixed issue with social default access and multi space tennany 2022-07-11 23:42:26 +02:00
Mikhail5555
9d6a5efa72 Update migration_sqlite-postgres.md 2022-07-11 23:14:55 +02:00
Mikhail5555
aaa0520a6d Update migration_sqlite-postgres.md 2022-07-11 23:12:42 +02:00
Mikhail5555
eb0f231a80 Create migration_sqlite-postgres.md 2022-07-11 23:09:41 +02:00
vabene1111
17f3da5a37 removed dead invite link button from system page 2022-07-11 14:54:00 +02:00
vabene1111
608039b7e4 cookbookapp importer more or less broken (more) 2022-07-11 14:46:54 +02:00
vabene1111
bb424cc3d6 Merge pull request #1917 from smilerz/bookmarklet_fix
Bookmarklet fix
2022-07-11 14:28:08 +02:00
Mike Miller
9eaf0f9530 Translated using Weblate (German)
Currently translated at 96.9% (414 of 427 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2022-07-10 08:32:35 +00:00
Kalli_1
b44bb552e0 Translated using Weblate (German)
Currently translated at 96.9% (414 of 427 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2022-07-10 08:32:35 +00:00
smilerz
e40b73f420 deprecate get_recipe_from_source 2022-07-07 15:09:22 -05:00
vabene1111
5b3d8a3aaf Merge branch 'develop' 2022-07-07 19:38:32 +02:00
vabene1111
fd4051c04a fixed copy to clipboard 2022-07-07 19:16:16 +02:00
vabene1111
5f0fa24c2a Merge pull request #1908 from nough/patch-1
Update backup.md with manual process
2022-07-07 18:57:43 +02:00
vabene1111
0d676e1957 Merge pull request #1909 from smilerz/makenow_query_fix
fix makenow filter
2022-07-07 18:56:31 +02:00
vabene1111
8539e365fb Merge pull request #1915 from TandoorRecipes/dependabot/npm_and_yarn/vue/moment-2.29.4
Bump moment from 2.29.3 to 2.29.4 in /vue
2022-07-07 18:52:49 +02:00
dependabot[bot]
dd25ea748b Bump moment from 2.29.3 to 2.29.4 in /vue
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-07 16:50:54 +00:00
vabene1111
2b74c1c47b Merge pull request #1912 from TandoorRecipes/dependabot/pip/lxml-4.9.1
Bump lxml from 4.9.0 to 4.9.1
2022-07-07 18:50:23 +02:00
smilerz
b1c0334947 quick hack to allow scraper to work correctly 2022-07-07 07:50:57 -05:00
smilerz
25a41bd293 reverting scraper to just using wildmode 2022-07-07 06:43:07 -05:00
nough
ac25beddda Update backup.md
working restore function
2022-07-07 10:27:32 +01:00
nough
9d38186404 Update backup.md
updated with functional code
2022-07-07 10:16:52 +01:00
dependabot[bot]
51d9ffbb4e Bump lxml from 4.9.0 to 4.9.1
Bumps [lxml](https://github.com/lxml/lxml) from 4.9.0 to 4.9.1.
- [Release notes](https://github.com/lxml/lxml/releases)
- [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt)
- [Commits](https://github.com/lxml/lxml/compare/lxml-4.9.0...lxml-4.9.1)

---
updated-dependencies:
- dependency-name: lxml
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-06 21:47:07 +00:00
smilerz
e23d514d89 fix bookmarklet 2022-07-06 16:16:53 -05:00
nough
0697116a21 Update backup.md
Added comment about backing up when other containers are failing
2022-07-06 19:29:22 +01:00
Nidhal Brniyah
165bb00040 Translated using Weblate (Arabic)
Currently translated at 20.4% (108 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ar/
2022-07-06 14:32:36 +00:00
vabene1111
07947199c0 Merge pull request #1910 from TandoorRecipes/dependabot/pip/django-4.0.6
Bump django from 4.0.5 to 4.0.6
2022-07-06 09:07:04 +02:00
dependabot[bot]
92aadb4743 Bump django from 4.0.5 to 4.0.6
Bumps [django](https://github.com/django/django) from 4.0.5 to 4.0.6.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/4.0.5...4.0.6)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-05 22:39:26 +00:00
smilerz
bd89de6f4d fix makenow filter 2022-07-05 14:31:32 -05:00
vabene1111
dca567b5fa Added translation using Weblate (Arabic) 2022-07-05 12:04:35 +00:00
vabene1111
a015c2f566 Added translation using Weblate (Arabic) 2022-07-05 12:04:31 +00:00
vabene1111
946de2e7e3 updated scrapers 2022-07-05 09:01:40 +02:00
vabene1111
690c486bb2 zip files before download in file broswer
needs to be completly rewritten in the future but for now this is more secure
2022-07-04 14:39:53 +02:00
vabene1111
d9d0676bed temporarily disable table button in mavon editor 2022-07-01 11:58:28 +02:00
vabene1111
9c8a410e50 fixed non spaced page load 2022-07-01 11:03:53 +02:00
vabene1111
22296de03c Merge pull request #1885 from Jbonnett/feature/reset_inheritance_fix
Fixes #1857
2022-07-01 11:02:26 +02:00
vabene1111
9228f9c339 Merge pull request #1891 from TandoorRecipes/dependabot/pip/django-allauth-0.51.0
Bump django-allauth from 0.50.0 to 0.51.0
2022-07-01 08:56:29 +02:00
vabene1111
609d4477ae Merge pull request #1906 from TandoorRecipes/dependabot/pip/requests-2.28.1
Bump requests from 2.27.1 to 2.28.1
2022-07-01 08:56:11 +02:00
vabene1111
fc0cfe3133 Merge pull request #1905 from TandoorRecipes/dependabot/pip/pytest-factoryboy-2.5.0
Bump pytest-factoryboy from 2.4.0 to 2.5.0
2022-07-01 08:55:48 +02:00
vabene1111
ebe1aa33f3 Merge pull request #1904 from TandoorRecipes/dependabot/pip/django-4.0.5
Bump django from 4.0.4 to 4.0.5
2022-07-01 08:55:41 +02:00
dependabot[bot]
e451adbfdb Bump requests from 2.27.1 to 2.28.1
Bumps [requests](https://github.com/psf/requests) from 2.27.1 to 2.28.1.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.27.1...v2.28.1)

---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:55:07 +00:00
dependabot[bot]
852c64d9f4 Bump pytest-factoryboy from 2.4.0 to 2.5.0
Bumps [pytest-factoryboy](https://github.com/pytest-dev/pytest-factoryboy) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/pytest-dev/pytest-factoryboy/releases)
- [Changelog](https://github.com/pytest-dev/pytest-factoryboy/blob/master/CHANGES.rst)
- [Commits](https://github.com/pytest-dev/pytest-factoryboy/compare/2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: pytest-factoryboy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:55:02 +00:00
dependabot[bot]
d96b6dbefb Bump django from 4.0.4 to 4.0.5
Bumps [django](https://github.com/django/django) from 4.0.4 to 4.0.5.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/4.0.4...4.0.5)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:54:56 +00:00
vabene1111
fbbd57a4ae Merge pull request #1903 from TandoorRecipes/dependabot/pip/django-cors-headers-3.13.0
Bump django-cors-headers from 3.12.0 to 3.13.0
2022-07-01 08:54:48 +02:00
dependabot[bot]
e5cc990111 Bump django-allauth from 0.50.0 to 0.51.0
Bumps [django-allauth](https://github.com/pennersr/django-allauth) from 0.50.0 to 0.51.0.
- [Release notes](https://github.com/pennersr/django-allauth/releases)
- [Changelog](https://github.com/pennersr/django-allauth/blob/master/ChangeLog.rst)
- [Commits](https://github.com/pennersr/django-allauth/compare/0.50.0...0.51.0)

---
updated-dependencies:
- dependency-name: django-allauth
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:54:46 +00:00
vabene1111
78482313d8 Merge pull request #1902 from TandoorRecipes/dependabot/pip/bleach-5.0.1
Bump bleach from 5.0.0 to 5.0.1
2022-07-01 08:54:39 +02:00
vabene1111
5b601695e1 Merge pull request #1901 from TandoorRecipes/dependabot/pip/pytube-12.1.0
Bump pytube from 12.0.0 to 12.1.0
2022-07-01 08:54:34 +02:00
dependabot[bot]
d6a67335ed Bump django-cors-headers from 3.12.0 to 3.13.0
Bumps [django-cors-headers](https://github.com/adamchainz/django-cors-headers) from 3.12.0 to 3.13.0.
- [Release notes](https://github.com/adamchainz/django-cors-headers/releases)
- [Changelog](https://github.com/adamchainz/django-cors-headers/blob/main/HISTORY.rst)
- [Commits](https://github.com/adamchainz/django-cors-headers/compare/3.12.0...3.13.0)

---
updated-dependencies:
- dependency-name: django-cors-headers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:53:58 +00:00
dependabot[bot]
4f7b68c882 Bump bleach from 5.0.0 to 5.0.1
Bumps [bleach](https://github.com/mozilla/bleach) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/mozilla/bleach/releases)
- [Changelog](https://github.com/mozilla/bleach/blob/main/CHANGES)
- [Commits](https://github.com/mozilla/bleach/commits)

---
updated-dependencies:
- dependency-name: bleach
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:53:54 +00:00
dependabot[bot]
1359782d30 Bump pytube from 12.0.0 to 12.1.0
Bumps [pytube](https://github.com/pytube/pytube) from 12.0.0 to 12.1.0.
- [Release notes](https://github.com/pytube/pytube/releases)
- [Commits](https://github.com/pytube/pytube/compare/v12.0.0...v12.1.0)

---
updated-dependencies:
- dependency-name: pytube
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:53:51 +00:00
vabene1111
966bd5fd33 Merge pull request #1899 from TandoorRecipes/dependabot/pip/whitenoise-6.2.0
Bump whitenoise from 6.1.0 to 6.2.0
2022-07-01 08:53:49 +02:00
vabene1111
759264e1d5 Merge pull request #1900 from TandoorRecipes/dependabot/pip/django-filter-22.1
Bump django-filter from 21.1 to 22.1
2022-07-01 08:53:40 +02:00
vabene1111
65c0f3d786 Merge pull request #1888 from TandoorRecipes/dependabot/pip/recipe-scrapers-14.5.2
Bump recipe-scrapers from 14.2.0 to 14.5.2
2022-07-01 08:53:30 +02:00
dependabot[bot]
f1535b4b54 Bump django-filter from 21.1 to 22.1
Bumps [django-filter](https://github.com/carltongibson/django-filter) from 21.1 to 22.1.
- [Release notes](https://github.com/carltongibson/django-filter/releases)
- [Changelog](https://github.com/carltongibson/django-filter/blob/main/CHANGES.rst)
- [Commits](https://github.com/carltongibson/django-filter/compare/21.1...22.1)

---
updated-dependencies:
- dependency-name: django-filter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:43:55 +00:00
dependabot[bot]
fcb5f51a78 Bump whitenoise from 6.1.0 to 6.2.0
Bumps [whitenoise](https://github.com/evansd/whitenoise) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/evansd/whitenoise/releases)
- [Changelog](https://github.com/evansd/whitenoise/blob/main/docs/changelog.rst)
- [Commits](https://github.com/evansd/whitenoise/compare/6.1.0...6.2.0)

---
updated-dependencies:
- dependency-name: whitenoise
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 06:43:52 +00:00
vabene1111
50fc98dcb3 Merge pull request #1889 from TandoorRecipes/dependabot/pip/boto3-1.24.21
Bump boto3 from 1.24.0 to 1.24.21
2022-07-01 08:43:45 +02:00
vabene1111
c1a1fe1047 Merge pull request #1887 from TandoorRecipes/dependabot/pip/validators-0.20.0
Bump validators from 0.19.0 to 0.20.0
2022-07-01 08:43:29 +02:00
dependabot[bot]
b3a60f70ff Bump boto3 from 1.24.0 to 1.24.21
Bumps [boto3](https://github.com/boto/boto3) from 1.24.0 to 1.24.21.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.24.0...1.24.21)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 00:04:35 +00:00
dependabot[bot]
5ee0033983 Bump recipe-scrapers from 14.2.0 to 14.5.2
Bumps [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) from 14.2.0 to 14.5.2.
- [Release notes](https://github.com/hhursev/recipe-scrapers/releases)
- [Commits](https://github.com/hhursev/recipe-scrapers/compare/14.2.0...14.5.2)

---
updated-dependencies:
- dependency-name: recipe-scrapers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 00:04:26 +00:00
dependabot[bot]
a28e653386 Bump validators from 0.19.0 to 0.20.0
Bumps [validators](https://github.com/kvesteri/validators) from 0.19.0 to 0.20.0.
- [Release notes](https://github.com/kvesteri/validators/releases)
- [Changelog](https://github.com/kvesteri/validators/blob/master/CHANGES.rst)
- [Commits](https://github.com/kvesteri/validators/compare/0.19.0...0.20.0)

---
updated-dependencies:
- dependency-name: validators
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 00:04:22 +00:00
Joshua Bonnett
8d568526be Fixes #1857 2022-06-29 05:15:22 -07:00
vabene1111
6643008baf media query for navbar scrolling 2022-06-28 07:30:42 +02:00
vabene1111
44a19e03e8 fixed ingredient list step header duplication 2022-06-28 06:32:25 +02:00
vabene1111
b5207d91ba fixed navbar viewport issues 2022-06-28 06:19:58 +02:00
vabene1111
f1d54675c3 allow editing recipe source filed 2022-06-28 06:17:43 +02:00
vabene1111
b057b6006c add debounce to food search on recipe edit 2022-06-26 12:54:08 +02:00
vabene1111
f92a62da4e improved header show/hide for step name 2022-06-26 12:47:40 +02:00
vabene1111
27c695a393 allow disabling of ingredient overview 2022-06-26 12:36:37 +02:00
vabene1111
7945c1a431 fixed ingredient compontent 2022-06-26 12:18:13 +02:00
vabene1111
7c31cb9993 updated and compiled translations 2022-06-26 12:10:25 +02:00
vabene1111
f6d46cae79 Merge pull request #1866 from nicedevil007/nicedevil007-patch-1
Updates with more packages
2022-06-26 12:08:16 +02:00
César Blanco Guillamon
0e49615a40 Translated using Weblate (Spanish)
Currently translated at 53.4% (282 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/es/
2022-06-25 17:32:27 +00:00
Tomasz Klimczak
534792cd1a Translated using Weblate (Polish)
Currently translated at 100.0% (425 of 425 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-06-22 18:32:29 +00:00
Andreas Thor Lau
89891d11d7 Translated using Weblate (Danish)
Currently translated at 100.0% (414 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/da/
2022-06-20 19:32:27 +00:00
vabene1111
cb86ece0c4 fixed parse servings function 2022-06-20 16:53:14 +02:00
vabene1111
e7976fab46 show import links 2022-06-20 16:52:42 +02:00
vabene1111
11cb40702d cookmate fixes 2022-06-20 16:29:33 +02:00
vabene1111
877b7799df added proper login template for social auth 2022-06-20 15:40:42 +02:00
vabene1111
7f35d462b6 fixed url import servings 2022-06-20 15:25:23 +02:00
nicedevil007
fff5c2387b removed python3.9 from update (python3 is enough) 2022-06-18 23:02:03 +02:00
nicedevil007
3de6f6faf8 Added the "--no-input" to the collectstatic lines 2022-06-18 22:32:09 +02:00
nicedevil007
e6f80497a9 Updates with more packages
Updated the manual installation file to get everybody up and running.
There were missing requirements like the nginx installation and so on.

Now a first time linux user should be able to get this up and running.
2022-06-18 09:49:25 +02:00
vabene1111
6c122e4ed0 fixed autofocus on markdown editor 2022-06-16 16:21:35 +02:00
Kaibu
1836056bd1 Recipe edit icons on mobile 2022-06-15 17:33:03 +02:00
Kaibu
cdc95d8fd2 ingredient card cleanup 2022-06-15 16:42:28 +02:00
Kaibu
d3c3339d5e shopping modal ui fixes 2022-06-15 16:27:43 +02:00
Kaibu
50992d3411 Merge branch 'develop' of https://github.com/TandoorRecipes/recipes into develop 2022-06-15 15:56:25 +02:00
Kaibu
2ae3e7f5b9 reactivated shopping list swipe only on food name 2022-06-15 15:56:18 +02:00
vabene1111
99ea193237 fixed url breaking recipe view 2022-06-15 15:47:52 +02:00
vabene1111
3427f7bbea fixed new limit recipe create 2022-06-15 15:37:20 +02:00
vabene1111
44704be22b fixed limit check for new recipes 2022-06-15 15:36:10 +02:00
vabene1111
356dec636f fixed ingredient paste and plan share serialize 2022-06-14 21:48:17 +02:00
vabene1111
355f181574 added youtube import 2022-06-14 21:37:59 +02:00
vabene1111
b365f9adc1 Merge pull request #1829 from astappiev/fixes
Some minor visual fixes
2022-06-14 21:03:00 +02:00
vabene1111
af1282c268 Merge pull request #1723 from vekunz/feature/optimize_printing
Fix some issues to improve the print output
2022-06-14 20:59:57 +02:00
vabene1111
9ccceb2199 Merge pull request #1815 from anu-codes/patch-1
Grammatical errors
2022-06-14 20:58:37 +02:00
vabene1111
bdea6440a8 Merge pull request #1854 from AliveDevil/feature/discussion-1832
Add django-scopes compatible django-admin dumpdata/loaddata commands
2022-06-14 20:56:52 +02:00
vabene1111
4e1f147b37 Merge pull request #1864 from anaymody/patch-1
Update index.md for capitalization and bold-face issues
2022-06-14 20:53:08 +02:00
anaymody
30d0d340c2 Update index.md
Added capitalization to line 52 and proposed some bold-face changes in lines 42, 44. 52. and 54.
2022-06-14 14:30:47 -04:00
vabene1111
d99748638d fixed broken filter on supermarket category lookups 2022-06-14 17:06:25 +02:00
vabene1111
889089b4cd fixed search defaults 2022-06-14 16:49:58 +02:00
vabene1111
e7de6f62b6 fixed permissions and tests 2022-06-14 16:20:37 +02:00
vabene1111
f02eac8ac6 remvoed ability to swipe shopping list as scrolling needs to be fixed 2022-06-14 15:13:46 +02:00
vabene1111
b30c282a13 remove exception details from api response 2022-06-14 15:07:31 +02:00
vabene1111
c2135de941 downgraded vue simple calendar 2022-06-14 12:08:43 +02:00
vabene1111
e2890d1363 Merge branch 'feature/multi-tennancy' into develop 2022-06-13 20:20:49 +02:00
Mike Miller
0dc2abbdd8 Translated using Weblate (German)
Currently translated at 97.8% (405 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2022-06-10 19:32:26 +00:00
vabene1111
deeed4b65b testes and fixes for space, userspace and invitelink apis 2022-06-09 22:02:58 +02:00
vabene1111
30e4ee855c switch space method signature change and test 2022-06-09 18:18:57 +02:00
vabene1111
2ab1560aed fixed user name api filter 2022-06-09 17:31:17 +02:00
vabene1111
d5b7d440fe fixed user preference api endpoint 2022-06-08 17:48:23 +02:00
Kaibu
df88b1ddd2 recipe switcher mobile ui height 2022-06-08 17:40:59 +02:00
vabene1111
e368488933 deprecated all old vue stuff and working on tests 2022-06-07 20:08:32 +02:00
vabene1111
37f0f7a0b7 added endpoint for space switching 2022-06-06 18:34:40 +02:00
vabene1111
e2b887b449 lots of fixes and stuff 2022-06-06 18:21:15 +02:00
Daniel
d653b8f9e6 Translated using Weblate (Portuguese (Brazil))
Currently translated at 4.8% (20 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pt_BR/
2022-06-05 14:49:41 +00:00
vabene1111
b8f74af41c add supporting options to readme 2022-06-02 16:54:07 +02:00
vabene1111
07f78bb7b8 space management page progress 2022-06-02 16:20:52 +02:00
AliveDevil
1679d820a7 Add django-admin export and import commands, making dump-data and loaddata django-scopes compatible 2022-06-02 14:26:28 +02:00
Oliver Cervera
b3bbb0b156 Translated using Weblate (Italian)
Currently translated at 57.7% (239 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/it/
2022-06-01 22:32:20 +00:00
Oliver Cervera
8afd73394d Translated using Weblate (Italian)
Currently translated at 82.1% (434 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/it/
2022-06-01 22:32:20 +00:00
vabene1111
2afab2aec8 invite link basics 2022-06-01 17:42:07 +02:00
vabene1111
f41e4c62d4 space manage users and permissions 2022-06-01 17:01:13 +02:00
vabene1111
c804064155 Merge branch 'develop' into feature/multi-tennancy 2022-06-01 15:36:26 +02:00
vabene1111
eeee36844d Merge pull request #1849 from TandoorRecipes/dependabot/npm_and_yarn/vue/webpack-bundle-tracker-1.5.0
Bump webpack-bundle-tracker from 1.4.0 to 1.5.0 in /vue
2022-06-01 13:47:14 +02:00
vabene1111
d4d4495f2b Merge pull request #1850 from TandoorRecipes/dependabot/npm_and_yarn/vue/typescript-4.7.2
Bump typescript from 4.5.5 to 4.7.2 in /vue
2022-06-01 13:47:05 +02:00
dependabot[bot]
0eee2d8ba5 Bump typescript from 4.5.5 to 4.7.2 in /vue
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.5.5 to 4.7.2.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.5.5...v4.7.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 05:52:58 +00:00
dependabot[bot]
fbfe00bfec Bump webpack-bundle-tracker from 1.4.0 to 1.5.0 in /vue
Bumps [webpack-bundle-tracker](https://github.com/django-webpack/webpack-bundle-tracker) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/django-webpack/webpack-bundle-tracker/releases)
- [Commits](https://github.com/django-webpack/webpack-bundle-tracker/compare/1.4.0...1.5.0)

---
updated-dependencies:
- dependency-name: webpack-bundle-tracker
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 05:52:00 +00:00
vabene1111
6e70bc3b5d Merge pull request #1848 from TandoorRecipes/dependabot/pip/boto3-1.24.0
Bump boto3 from 1.23.10 to 1.24.0
2022-06-01 07:47:27 +02:00
vabene1111
2dde6ae663 Merge pull request #1846 from TandoorRecipes/dependabot/pip/lxml-4.9.0
Bump lxml from 4.8.0 to 4.9.0
2022-06-01 07:47:20 +02:00
vabene1111
9bda43a670 Merge pull request #1847 from TandoorRecipes/dependabot/pip/pytest-factoryboy-2.4.0
Bump pytest-factoryboy from 2.3.1 to 2.4.0
2022-06-01 07:47:13 +02:00
vabene1111
ba49535bba Merge pull request #1851 from TandoorRecipes/dependabot/npm_and_yarn/vue/vue-cli-plugin-i18n-2.3.1
Bump vue-cli-plugin-i18n from 0.6.1 to 2.3.1 in /vue
2022-06-01 07:47:05 +02:00
vabene1111
21b69f06e5 Merge pull request #1845 from TandoorRecipes/dependabot/pip/recipe-scrapers-14.2.0
Bump recipe-scrapers from 14.1.0 to 14.2.0
2022-06-01 07:46:52 +02:00
dependabot[bot]
1390b01f07 Bump vue-cli-plugin-i18n from 0.6.1 to 2.3.1 in /vue
Bumps [vue-cli-plugin-i18n](https://github.com/intlify/vue-cli-plugin-i18n) from 0.6.1 to 2.3.1.
- [Release notes](https://github.com/intlify/vue-cli-plugin-i18n/releases)
- [Changelog](https://github.com/intlify/vue-cli-plugin-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-cli-plugin-i18n/compare/v0.6.1...v2.3.1)

---
updated-dependencies:
- dependency-name: vue-cli-plugin-i18n
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 00:14:43 +00:00
dependabot[bot]
b9dc0da249 Bump boto3 from 1.23.10 to 1.24.0
Bumps [boto3](https://github.com/boto/boto3) from 1.23.10 to 1.24.0.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.23.10...1.24.0)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 00:05:18 +00:00
dependabot[bot]
6615bbb532 Bump pytest-factoryboy from 2.3.1 to 2.4.0
Bumps [pytest-factoryboy](https://github.com/pytest-dev/pytest-factoryboy) from 2.3.1 to 2.4.0.
- [Release notes](https://github.com/pytest-dev/pytest-factoryboy/releases)
- [Changelog](https://github.com/pytest-dev/pytest-factoryboy/blob/master/CHANGES.rst)
- [Commits](https://github.com/pytest-dev/pytest-factoryboy/compare/2.3.1...2.4.0)

---
updated-dependencies:
- dependency-name: pytest-factoryboy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 00:05:09 +00:00
dependabot[bot]
b8ef6b3888 Bump lxml from 4.8.0 to 4.9.0
Bumps [lxml](https://github.com/lxml/lxml) from 4.8.0 to 4.9.0.
- [Release notes](https://github.com/lxml/lxml/releases)
- [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt)
- [Commits](https://github.com/lxml/lxml/compare/lxml-4.8.0...lxml-4.9.0)

---
updated-dependencies:
- dependency-name: lxml
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 00:05:03 +00:00
dependabot[bot]
1fc9f74e60 Bump recipe-scrapers from 14.1.0 to 14.2.0
Bumps [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) from 14.1.0 to 14.2.0.
- [Release notes](https://github.com/hhursev/recipe-scrapers/releases)
- [Commits](https://github.com/hhursev/recipe-scrapers/compare/14.1.0...14.2.0)

---
updated-dependencies:
- dependency-name: recipe-scrapers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 00:04:55 +00:00
vabene1111
ded092ed23 baiscs of space edit page 2022-05-31 21:52:59 +02:00
vabene1111
007b7294d9 join and leave spaces 2022-05-31 20:38:53 +02:00
vabene1111
b3fcfdfc96 space switcher 2022-05-31 17:48:43 +02:00
vabene1111
151461508f multi space membership basics 2022-05-31 17:38:12 +02:00
vabene1111
9affc583a3 add token endpoint 2022-05-31 15:43:04 +02:00
vabene1111
cac72df7ba refactored recipe from source endpoint 2022-05-31 15:22:27 +02:00
Bekhruz Khazratov
a6c81d8168 Translated using Weblate (Russian)
Currently translated at 82.6% (342 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/ru/
2022-05-31 08:32:18 +00:00
Jesse
7aa3e49e8c Translated using Weblate (Dutch)
Currently translated at 100.0% (414 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2022-05-31 08:32:18 +00:00
Jesse
ab378f5332 Translated using Weblate (Dutch)
Currently translated at 100.0% (528 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/nl/
2022-05-31 08:32:18 +00:00
vabene1111
24b0d7f8e6 removed unused library 2022-05-30 22:10:25 +02:00
vabene1111
5561a9621b copy past 2022-05-30 21:58:22 +02:00
vabene1111
3512ab7515 update wokflow files 2022-05-30 21:53:59 +02:00
vabene1111
12df4abc80 updating ci 2022-05-30 21:48:34 +02:00
vabene1111
f768aef0b9 fixed some breaking changes due to dependency updates 2022-05-30 21:42:30 +02:00
vabene1111
a6dcef4467 Merge pull request #1756 from TandoorRecipes/dependabot/npm_and_yarn/vue/axios-0.27.2
Bump axios from 0.26.1 to 0.27.2 in /vue
2022-05-30 19:56:34 +02:00
dependabot[bot]
699a6a42be Bump axios from 0.26.1 to 0.27.2 in /vue
Bumps [axios](https://github.com/axios/axios) from 0.26.1 to 0.27.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.26.1...v0.27.2)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:54:21 +00:00
vabene1111
9380e376c6 Merge pull request #1840 from TandoorRecipes/dependabot/pip/whitenoise-6.1.0
Bump whitenoise from 6.0.0 to 6.1.0
2022-05-30 19:53:51 +02:00
dependabot[bot]
04dd51d089 Bump whitenoise from 6.0.0 to 6.1.0
Bumps [whitenoise](https://github.com/evansd/whitenoise) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/evansd/whitenoise/releases)
- [Changelog](https://github.com/evansd/whitenoise/blob/main/docs/changelog.rst)
- [Commits](https://github.com/evansd/whitenoise/compare/6.0.0...6.1.0)

---
updated-dependencies:
- dependency-name: whitenoise
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:53:09 +00:00
vabene1111
fe19f81bcd Merge pull request #1838 from TandoorRecipes/dependabot/pip/pillow-9.1.1
Bump pillow from 9.0.1 to 9.1.1
2022-05-30 19:52:48 +02:00
vabene1111
e3711f121f Merge pull request #1841 from TandoorRecipes/dependabot/pip/pytest-factoryboy-2.3.1
Bump pytest-factoryboy from 2.1.0 to 2.3.1
2022-05-30 19:52:34 +02:00
vabene1111
075fd2fd9b Merge pull request #1843 from TandoorRecipes/dependabot/pip/boto3-1.23.10
Bump boto3 from 1.21.31 to 1.23.10
2022-05-30 19:52:20 +02:00
dependabot[bot]
662cfde691 Bump pillow from 9.0.1 to 9.1.1
Bumps [pillow](https://github.com/python-pillow/Pillow) from 9.0.1 to 9.1.1.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/9.0.1...9.1.1)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:51:46 +00:00
dependabot[bot]
0a6264228a Bump pytest-factoryboy from 2.1.0 to 2.3.1
Bumps [pytest-factoryboy](https://github.com/pytest-dev/pytest-factoryboy) from 2.1.0 to 2.3.1.
- [Release notes](https://github.com/pytest-dev/pytest-factoryboy/releases)
- [Changelog](https://github.com/pytest-dev/pytest-factoryboy/blob/master/CHANGES.rst)
- [Commits](https://github.com/pytest-dev/pytest-factoryboy/compare/2.1.0...2.3.1)

---
updated-dependencies:
- dependency-name: pytest-factoryboy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:51:37 +00:00
dependabot[bot]
3f67c6d220 Bump boto3 from 1.21.31 to 1.23.10
Bumps [boto3](https://github.com/boto/boto3) from 1.21.31 to 1.23.10.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.21.31...1.23.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:51:30 +00:00
vabene1111
4fa6fc10f8 Merge pull request #1839 from TandoorRecipes/dependabot/pip/bleach-5.0.0
Bump bleach from 4.1.0 to 5.0.0
2022-05-30 19:51:08 +02:00
vabene1111
ada811a868 Merge pull request #1837 from TandoorRecipes/dependabot/pip/markdown-3.3.7
Bump markdown from 3.3.6 to 3.3.7
2022-05-30 19:50:55 +02:00
dependabot[bot]
00132c6afa Bump markdown from 3.3.6 to 3.3.7
Bumps [markdown](https://github.com/Python-Markdown/markdown) from 3.3.6 to 3.3.7.
- [Release notes](https://github.com/Python-Markdown/markdown/releases)
- [Commits](https://github.com/Python-Markdown/markdown/compare/3.3.6...3.3.7)

---
updated-dependencies:
- dependency-name: markdown
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:50:42 +00:00
dependabot[bot]
da1af693a2 Bump bleach from 4.1.0 to 5.0.0
Bumps [bleach](https://github.com/mozilla/bleach) from 4.1.0 to 5.0.0.
- [Release notes](https://github.com/mozilla/bleach/releases)
- [Changelog](https://github.com/mozilla/bleach/blob/main/CHANGES)
- [Commits](https://github.com/mozilla/bleach/compare/v4.1.0...v5.0.0)

---
updated-dependencies:
- dependency-name: bleach
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:50:31 +00:00
vabene1111
a9d9c03cc0 Merge pull request #1836 from TandoorRecipes/dependabot/pip/recipe-scrapers-14.1.0
Bump recipe-scrapers from 13.32.1 to 14.1.0
2022-05-30 19:50:18 +02:00
vabene1111
0e1522db12 Merge pull request #1835 from TandoorRecipes/dependabot/pip/cryptography-37.0.2
Bump cryptography from 37.0.1 to 37.0.2
2022-05-30 19:50:14 +02:00
vabene1111
df04d6b58d Merge pull request #1834 from TandoorRecipes/dependabot/pip/django-cors-headers-3.12.0
Bump django-cors-headers from 3.11.0 to 3.12.0
2022-05-30 19:50:09 +02:00
vabene1111
b098b6d148 Merge pull request #1833 from TandoorRecipes/dependabot/pip/django-auth-ldap-4.1.0
Bump django-auth-ldap from 4.0.0 to 4.1.0
2022-05-30 19:50:04 +02:00
dependabot[bot]
24bc6a1a8a Bump recipe-scrapers from 13.32.1 to 14.1.0
Bumps [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) from 13.32.1 to 14.1.0.
- [Release notes](https://github.com/hhursev/recipe-scrapers/releases)
- [Commits](https://github.com/hhursev/recipe-scrapers/compare/13.32.1...14.1.0)

---
updated-dependencies:
- dependency-name: recipe-scrapers
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:48:56 +00:00
dependabot[bot]
64abf6d785 Bump django-cors-headers from 3.11.0 to 3.12.0
Bumps [django-cors-headers](https://github.com/adamchainz/django-cors-headers) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/adamchainz/django-cors-headers/releases)
- [Changelog](https://github.com/adamchainz/django-cors-headers/blob/main/HISTORY.rst)
- [Commits](https://github.com/adamchainz/django-cors-headers/compare/3.11.0...3.12.0)

---
updated-dependencies:
- dependency-name: django-cors-headers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:48:56 +00:00
vabene1111
f156722456 Merge pull request #1752 from TandoorRecipes/dependabot/pip/pytest-7.1.2
Bump pytest from 7.1.1 to 7.1.2
2022-05-30 19:48:16 +02:00
dependabot[bot]
d641a3fa48 Bump cryptography from 37.0.1 to 37.0.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 37.0.1 to 37.0.2.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/37.0.1...37.0.2)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:47:17 +00:00
dependabot[bot]
29760defd0 Bump django-auth-ldap from 4.0.0 to 4.1.0
Bumps [django-auth-ldap](https://github.com/django-auth-ldap/django-auth-ldap) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/django-auth-ldap/django-auth-ldap/releases)
- [Changelog](https://github.com/django-auth-ldap/django-auth-ldap/blob/master/docs/changes.rst)
- [Commits](https://github.com/django-auth-ldap/django-auth-ldap/compare/4.0.0...4.1.0)

---
updated-dependencies:
- dependency-name: django-auth-ldap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:47:16 +00:00
dependabot[bot]
5eb822089d Bump pytest from 7.1.1 to 7.1.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.1 to 7.1.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.1.1...7.1.2)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:47:07 +00:00
vabene1111
53414ec1df Merge pull request #1753 from TandoorRecipes/dependabot/pip/jinja2-3.1.2
Bump jinja2 from 3.1.1 to 3.1.2
2022-05-30 19:46:47 +02:00
vabene1111
cd3f0ba739 Merge pull request #1751 from TandoorRecipes/dependabot/pip/beautifulsoup4-4.11.1
Bump beautifulsoup4 from 4.10.0 to 4.11.1
2022-05-30 19:46:42 +02:00
vabene1111
74152d2409 Merge pull request #1750 from TandoorRecipes/dependabot/pip/django-scopes-1.2.0.post1
Bump django-scopes from 1.2.0 to 1.2.0.post1
2022-05-30 19:46:37 +02:00
dependabot[bot]
8f7a4a31c8 Bump beautifulsoup4 from 4.10.0 to 4.11.1
Bumps [beautifulsoup4](https://www.crummy.com/software/BeautifulSoup/bs4/) from 4.10.0 to 4.11.1.

---
updated-dependencies:
- dependency-name: beautifulsoup4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:46:32 +00:00
dependabot[bot]
c5f11c1625 Bump jinja2 from 3.1.1 to 3.1.2
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.1...3.1.2)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-30 17:46:20 +00:00
vabene1111
f0eb295696 Merge pull request #1754 from TandoorRecipes/dependabot/pip/django-webpack-loader-1.5.0
Bump django-webpack-loader from 1.4.1 to 1.5.0
2022-05-30 19:45:54 +02:00
vabene1111
c86fe0690b Merge pull request #1755 from TandoorRecipes/dependabot/npm_and_yarn/vue/workbox-precaching-6.5.3
Bump workbox-precaching from 6.5.2 to 6.5.3 in /vue
2022-05-30 19:45:50 +02:00
vabene1111
2f088d03bb Merge pull request #1757 from TandoorRecipes/dependabot/npm_and_yarn/vue/vue-cookies-1.8.1
Bump vue-cookies from 1.7.4 to 1.8.1 in /vue
2022-05-30 19:45:42 +02:00
vabene1111
1195dd445a Merge pull request #1759 from TandoorRecipes/dependabot/npm_and_yarn/vue/eslint-plugin-vue-8.7.1
Bump eslint-plugin-vue from 8.5.0 to 8.7.1 in /vue
2022-05-30 19:45:36 +02:00
vabene1111
71c5835909 Added translation using Weblate (Ukrainian) 2022-05-30 16:42:02 +00:00
vabene1111
423e042492 Added translation using Weblate (Ukrainian) 2022-05-30 16:41:36 +00:00
Oleh Astappiev
37c87b4375 fix: ingredients table out of page bounds 2022-05-29 18:25:18 +02:00
Oleh Astappiev
43666e1f63 fix: improve recipe toolbar visualization on mobile and position of elements 2022-05-29 17:42:40 +02:00
Oleh Astappiev
d5dd64acd2 fix: improve buttons visualization on mobile 2022-05-29 17:41:51 +02:00
Oleh Astappiev
b0c3ea0934 fix: make menu icons centered on mobile 2022-05-29 17:16:18 +02:00
Oleh Astappiev
ab446590a2 fix: add some space in multi-row lists of elements on mobile 2022-05-29 17:02:21 +02:00
Oleh Astappiev
3478ff17f8 fix: recipe's step header out of view on mobile in edit mode 2022-05-29 16:56:13 +02:00
Frank Poppe
932e7c8912 Translated using Weblate (Spanish)
Currently translated at 37.4% (155 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/es/
2022-05-28 16:32:21 +00:00
Frank Poppe
6e7a769d79 Translated using Weblate (German)
Currently translated at 89.6% (371 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2022-05-28 16:32:21 +00:00
Frank Poppe
8602de6ce1 Translated using Weblate (Spanish)
Currently translated at 52.6% (278 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/es/
2022-05-28 16:32:21 +00:00
Tobias Reinmann
faee71943f Translated using Weblate (German)
Currently translated at 90.9% (480 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/de/
2022-05-28 16:32:21 +00:00
vabene1111
0e2a27ad41 Merge branch 'develop' 2022-05-25 18:53:18 +02:00
vabene1111
c064e8970f compiled messages 2022-05-25 17:58:29 +02:00
Krisztian Doka
b8ef7ae39d Translated using Weblate (Hungarian)
Currently translated at 92.2% (487 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/hu/
2022-05-24 20:32:14 +00:00
Krisztian Doka
702f3de061 Added translation using Weblate (Hungarian) 2022-05-23 19:50:50 +00:00
Ramon Aixa Juan
f278d7f6d0 Translated using Weblate (Spanish)
Currently translated at 8.2% (34 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/es/
2022-05-23 11:32:17 +00:00
Ramon Aixa Juan
221c1b523b Translated using Weblate (Spanish)
Currently translated at 52.2% (276 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/es/
2022-05-23 11:32:17 +00:00
Ramon Aixa Juan
d00b6a2e85 Translated using Weblate (Catalan)
Currently translated at 91.0% (481 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ca/
2022-05-22 11:20:51 +00:00
César Blanco Guillamon
e03c285f14 Translated using Weblate (Spanish)
Currently translated at 5.3% (22 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/es/
2022-05-21 17:32:19 +00:00
Tomasz Klimczak
0ec1f334c0 Translated using Weblate (Polish)
Currently translated at 100.0% (414 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-05-21 17:32:19 +00:00
Laura
b637cbeabc Translated using Weblate (French)
Currently translated at 90.3% (374 of 414 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2022-05-21 17:32:18 +00:00
César Blanco Guillamon
943f873855 Translated using Weblate (Spanish)
Currently translated at 51.3% (271 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/es/
2022-05-19 10:10:33 +00:00
César Blanco Guillamon
49cebb400a Added translation using Weblate (Spanish) 2022-05-19 10:10:33 +00:00
Anu
0ed9225c05 Grammatical errors
Spotted several errors in sentence structure, punctuation, capitalization and other grammatical issues. Most changes are minor and any sentences that have been restructured have been re-written with great contemplation to keep the original meaning intact. This is my first open source contribution attempt so please let me know if this is appropriate. I am willing to help improve other pages of the docs as well if this work is considered helpful!
2022-05-19 00:27:24 +05:30
vabene1111
991fbdad3a fixed localization of create shopping auto form 2022-05-18 16:49:25 +02:00
vabene1111
34e95cd25b improved mobile rendering on ingerdient editor 2022-05-18 16:44:27 +02:00
vabene1111
8bc06fef34 Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-05-18 16:27:11 +02:00
vabene1111
6aba5c3661 fixed plan to eat tag delimeter 2022-05-18 16:27:07 +02:00
vabene1111
876bd49ee5 Merge pull request #1793 from smilerz/url_import_test
fixed spuce eats test
2022-05-18 16:25:30 +02:00
vabene1111
9435c5a380 changed order for reverse auth middleware 2022-05-18 16:09:37 +02:00
vabene1111
94c915e23a fixed advanced search field configuration cookie expiery 2022-05-18 16:06:55 +02:00
vabene1111
9ac8641c13 dont make first step header as default if others are not 2022-05-18 15:55:58 +02:00
vabene1111
0fe06cf2df fixed random search ordering 2022-05-18 15:54:02 +02:00
vabene1111
f872f994f1 fixed import failure with leading commas in input strings 2022-05-18 15:29:03 +02:00
vabene1111
87c2ff73e8 Merge branch 'develop' 2022-05-18 14:38:01 +02:00
Gabriel Tapias
27bb4c9bb8 Translated using Weblate (Spanish)
Currently translated at 48.1% (254 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/es/
2022-05-17 21:32:15 +00:00
dependabot[bot]
c10e0fd7bc Bump eslint-plugin-vue from 8.5.0 to 8.7.1 in /vue
Bumps [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) from 8.5.0 to 8.7.1.
- [Release notes](https://github.com/vuejs/eslint-plugin-vue/releases)
- [Commits](https://github.com/vuejs/eslint-plugin-vue/compare/v8.5.0...v8.7.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-vue
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-17 20:13:02 +00:00
dependabot[bot]
48d302020c Bump vue-cookies from 1.7.4 to 1.8.1 in /vue
Bumps [vue-cookies](https://github.com/cmp-cc/vue-cookies) from 1.7.4 to 1.8.1.
- [Release notes](https://github.com/cmp-cc/vue-cookies/releases)
- [Commits](https://github.com/cmp-cc/vue-cookies/compare/v1.7.4...v1.8.1)

---
updated-dependencies:
- dependency-name: vue-cookies
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-17 20:12:23 +00:00
dependabot[bot]
b31b3ccd23 Bump workbox-precaching from 6.5.2 to 6.5.3 in /vue
Bumps [workbox-precaching](https://github.com/googlechrome/workbox) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/googlechrome/workbox/releases)
- [Commits](https://github.com/googlechrome/workbox/compare/v6.5.2...v6.5.3)

---
updated-dependencies:
- dependency-name: workbox-precaching
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-17 20:11:21 +00:00
vabene1111
ac647c5ee8 more JS nonsense 2022-05-17 22:00:36 +02:00
vabene1111
3cec891aa1 added missing dependency 2022-05-17 21:57:43 +02:00
vabene1111
3633b9724b fixed image deletion error 2022-05-17 21:53:10 +02:00
vabene1111
420b5c093f updated some dependencies 2022-05-17 21:43:52 +02:00
vabene1111
9bb55dd746 Merge pull request #1758 from TandoorRecipes/dependabot/npm_and_yarn/vue/kangc/v-md-editor-1.7.11
Bump @kangc/v-md-editor from 1.7.9 to 1.7.11 in /vue
2022-05-17 21:38:00 +02:00
dependabot[bot]
1759ad3587 Bump @kangc/v-md-editor from 1.7.9 to 1.7.11 in /vue
Bumps [@kangc/v-md-editor](https://github.com/code-farmer-i/vue-markdown-editor) from 1.7.9 to 1.7.11.
- [Release notes](https://github.com/code-farmer-i/vue-markdown-editor/releases)
- [Changelog](https://github.com/code-farmer-i/vue-markdown-editor/blob/dev/docs/changelog.md)
- [Commits](https://github.com/code-farmer-i/vue-markdown-editor/compare/v1.7.9...v1.7.11)

---
updated-dependencies:
- dependency-name: "@kangc/v-md-editor"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-17 19:30:34 +00:00
vabene1111
956693b7ca changed view mode of file viewer downloadable files
changed it so that the file is always downloaded so that opened files do not open in the application context (to prevent possible XSS issues)
2022-05-17 21:27:40 +02:00
vabene1111
7b2117c019 improved output sanitization of several views 2022-05-17 21:24:27 +02:00
vabene1111
d48fe26a35 added url validation to all server requests 2022-05-17 18:04:43 +02:00
Kaibu
7fd5fca0cf changed mobile logo to png version aswell 2022-05-13 15:11:04 +02:00
smilerz
37e215a4ea fixed spuce eats test 2022-05-11 14:18:14 -05:00
dependabot[bot]
ab5400efad Bump django-webpack-loader from 1.4.1 to 1.5.0
Bumps [django-webpack-loader](https://github.com/django-webpack/django-webpack-loader) from 1.4.1 to 1.5.0.
- [Release notes](https://github.com/django-webpack/django-webpack-loader/releases)
- [Changelog](https://github.com/django-webpack/django-webpack-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/django-webpack/django-webpack-loader/compare/1.4.1...1.5.0)

---
updated-dependencies:
- dependency-name: django-webpack-loader
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-11 18:43:24 +00:00
dependabot[bot]
258ecd476c Bump django-scopes from 1.2.0 to 1.2.0.post1
Bumps [django-scopes](https://github.com/raphaelm/django-scopes) from 1.2.0 to 1.2.0.post1.
- [Release notes](https://github.com/raphaelm/django-scopes/releases)
- [Commits](https://github.com/raphaelm/django-scopes/commits)

---
updated-dependencies:
- dependency-name: django-scopes
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-11 18:43:07 +00:00
vabene1111
378938812c update recipe scrapers 2022-05-11 20:42:28 +02:00
vabene1111
60b494abeb workflow name 2022-05-11 20:30:17 +02:00
vabene1111
34be1dc1d7 removed notification from raspi build 2022-05-11 20:14:53 +02:00
vabene1111
d89a4620f0 meal plan remove old add to shopping 2022-05-11 19:59:04 +02:00
vabene1111
dea83b5720 fixed duplication of values in recipe editor 2022-05-11 19:31:44 +02:00
vabene1111
d9ebe3e0fb fixed original text rendering in recipe edito view 2022-05-11 19:25:48 +02:00
vabene1111
135dde247f fixed static path generation 2022-05-11 19:17:40 +02:00
vabene1111
eb7a667202 fixed cookmate importer 2022-05-11 19:10:56 +02:00
Kaibu
b3cc9967f5 Merge branch 'develop' of https://github.com/TandoorRecipes/recipes into develop 2022-05-11 17:10:18 +02:00
Kaibu
7276cea3d5 multiple ux fixes 2022-05-11 17:10:12 +02:00
vabene1111
c0c996622e made shopping new entry translatable 2022-05-11 17:06:34 +02:00
vabene1111
5556555bca fixed paprika servings import 2022-05-11 17:05:47 +02:00
vabene1111
55a84494c9 fixed issue with plan to eat importer 2022-05-11 16:53:20 +02:00
vabene1111
74d778dcb8 compiled messages 2022-05-11 16:45:34 +02:00
vabene1111
156d68f1b8 added link to shopping recipes 2022-05-11 16:42:52 +02:00
vabene1111
cb59a6340d Merge pull request #1788 from gloriousDan/fix-import
Fix import with recipe-scrapers
2022-05-11 16:37:41 +02:00
vabene1111
5eb013cc2f Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-05-11 16:22:18 +02:00
vabene1111
dafb26b500 updated raspi docs 2022-05-11 16:22:13 +02:00
vabene1111
d9416a42dc Merge pull request #1786 from gloriousDan/dockerfile-armv7
Build pillow for armv7/ raspi
2022-05-11 16:17:45 +02:00
Jesse
ad88eff9e3 Translated using Weblate (Dutch)
Currently translated at 100.0% (528 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/nl/
2022-05-10 15:32:17 +00:00
zeon
4d4f623adf Translated using Weblate (Bulgarian)
Currently translated at 100.0% (412 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/bg/
2022-05-10 15:32:16 +00:00
Mathias Rasmussen
ac9c9cd4e3 Translated using Weblate (Danish)
Currently translated at 100.0% (528 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/da/
2022-05-10 15:32:15 +00:00
Jesse
580eeef6b7 Translated using Weblate (Dutch)
Currently translated at 100.0% (412 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2022-05-10 15:32:13 +00:00
zeon
f25f5a26cf Translated using Weblate (Bulgarian)
Currently translated at 100.0% (528 of 528 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/bg/
2022-05-10 15:32:11 +00:00
Mathias Rasmussen
972d43c2a2 Translated using Weblate (Danish)
Currently translated at 100.0% (412 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/da/
2022-05-10 15:32:09 +00:00
Daniel Schulz
2a7475c435 Call scrape_me first when scraping from url 2022-05-10 00:08:37 +02:00
Daniel Schulz
71b41efe6c Build pillow for armv7/ raspi 2022-05-09 13:24:59 +02:00
zeon
33a7fee1cc Added translation using Weblate (Bulgarian) 2022-05-08 21:25:53 +00:00
zeon
fa7fb644ea Added translation using Weblate (Bulgarian) 2022-05-08 20:44:02 +00:00
Mathias Rasmussen
13b996171a Translated using Weblate (Danish)
Currently translated at 1.9% (8 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/da/
2022-05-07 16:49:26 +00:00
Kim Dannemand
77bb3870bf Translated using Weblate (Danish)
Currently translated at 1.9% (8 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/da/
2022-05-07 16:49:26 +00:00
vabene1111
9863303a5e Merge remote-tracking branch 'origin/develop' into develop 2022-05-06 20:32:14 +02:00
vabene1111
0caccc3da8 updated it and ru languages 2022-05-06 20:31:57 +02:00
vabene1111
b75427b86d Added translation using Weblate (Danish) 2022-05-06 18:30:41 +00:00
vabene1111
054c4ec61a Added translation using Weblate (Danish) 2022-05-06 18:30:05 +00:00
vabene1111
8da21f9914 added specific build files for raspi (armv7) 2022-05-06 20:28:20 +02:00
vabene1111
99ba512862 Merge branch 'beta' into develop 2022-05-06 20:24:27 +02:00
vabene1111
eab59fcbd8 Update docker-publish-latest-raspi.yml 2022-05-06 16:08:13 +02:00
vabene1111
484da2200e added some debug to auto add shopping signal 2022-05-06 15:34:28 +02:00
vabene1111
330bb6d954 testing extra raspi build 2022-05-06 15:07:54 +02:00
axeron2036
d4b6c8da04 Translated using Weblate (Russian)
Currently translated at 80.3% (331 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/ru/
2022-05-06 06:32:14 +00:00
Tomasz Klimczak
a5ef438cfe Translated using Weblate (Polish)
Currently translated at 100.0% (412 of 412 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-05-04 19:32:09 +00:00
vabene1111
de196c716b build test openssl 2022-05-04 20:33:27 +02:00
vabene1111
cb248a1f19 beta build test libressl 2022-05-04 20:33:10 +02:00
vabene1111
df2f1b2b7c testing armv7 build solutuin
taken from https://github.com/healthchecks/healthchecks/issues/568#issuecomment-942047344
2022-05-04 17:18:25 +02:00
vabene1111
36e26d8009 Merge branch 'master' into beta 2022-05-04 17:18:08 +02:00
vabene1111
a5973de02b Merge branch 'develop' 2022-05-04 17:11:35 +02:00
vabene1111
68f272bc25 fixed adding supermarket category to supermarket frontend desync 2022-05-04 15:20:40 +02:00
vabene1111
b66a5c1ee9 Merge branch 'develop' 2022-05-04 15:01:14 +02:00
vabene1111
bfc42638a4 fixed supermarket category ordering 2022-05-04 15:00:39 +02:00
vabene1111
a8c9689b43 fixed ability to disabled auto sync 2022-05-04 14:47:53 +02:00
vabene1111
26ff3f56ea Merge branch 'develop' into beta 2022-05-03 16:58:44 +02:00
vabene1111
a49993e399 testing new cryptography version 2022-05-03 16:58:39 +02:00
Tomasz Klimczak
9f42226224 Translated using Weblate (Polish)
Currently translated at 100.0% (395 of 395 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-05-02 22:32:09 +00:00
vabene1111
8f4c00df0b use old property as other sometimes fails 2022-05-02 15:52:15 +02:00
vabene1111
6cebec86c5 Merge branch 'master' into develop 2022-05-02 15:25:47 +02:00
vabene1111
8f5b017857 dont build arm 2022-05-01 21:51:57 +02:00
vabene1111
9915a3eebf Merge branch 'develop' 2022-05-01 13:09:48 +02:00
vabene1111
19c2d3bcf1 shopping description 2022-05-01 13:03:36 +02:00
vabene1111
9259f306ec final importer touches 2022-05-01 12:51:37 +02:00
vabene1111
483bc8f1b7 Merge branch 'develop' into beta 2022-04-29 21:58:13 +02:00
vabene1111
4f33101319 fixed empty step time error 2022-04-29 21:57:05 +02:00
vabene1111
3cef470134 made and compiled messages 2022-04-29 18:42:33 +02:00
vabene1111
ba493e3e19 Merge branch 'develop' into beta 2022-04-25 09:40:04 +02:00
Kaibu
93c53e5fc8 Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-04-24 12:52:06 +02:00
Kaibu
d931feadf5 supermarkets rework mostly done 2022-04-24 12:52:00 +02:00
vabene1111
fe32ff15b3 another toast fix 2022-04-24 12:46:17 +02:00
vabene1111
a44dea64b8 fixed toast error 2022-04-23 20:55:01 +02:00
Kaibu
54af76e9cf Merge branch 'develop' of https://github.com/vabene1111/recipes into develop
# Conflicts:
#	vue/src/apps/ShoppingListView/ShoppingListView.vue
2022-04-23 20:45:35 +02:00
Kaibu
fcfef255c1 shopping list supermarket rework 2022-04-23 20:44:46 +02:00
vabene1111
2914c20522 added space tier banner 2022-04-23 20:18:10 +02:00
vabene1111
825b7b7cf9 ingredient editor and parser 2022-04-23 19:58:40 +02:00
vabene1111
b9fb78c24d Merge pull request #1739 from ndbeals/develop
Fix image upload handler to use content-type
2022-04-23 19:55:08 +02:00
vabene1111
2fbce7d84d Merge pull request #1734 from Drumstickx/develop
Fix link in German locale
2022-04-23 19:53:47 +02:00
vabene1111
69a23f34b4 updated tests ingredient pagination 2022-04-23 18:54:23 +02:00
vabene1111
9f90306f6c at least basic ui for ingredient editor 2022-04-23 17:13:27 +02:00
vabene1111
1fb6f96571 minor shopping tweaks 2022-04-23 16:51:04 +02:00
vabene1111
0b8dd63510 small fixes 2022-04-23 15:27:21 +02:00
Kaibu
b79bc0d9a8 Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-04-23 14:47:14 +02:00
Kaibu
8149192455 shopping list and import view ux 2022-04-23 14:47:10 +02:00
vabene1111
66c0cc070a removed old shopping list 2022-04-23 14:43:03 +02:00
vabene1111
e2ab3a0efb fixed ingredient parser length issues 2022-04-23 14:15:06 +02:00
vabene1111
e0b7d1a8f0 added support for unit/amount at end of ingredient 2022-04-23 13:53:04 +02:00
vabene1111
012a1a7915 ingredient parser produces expected results again 2022-04-23 13:03:15 +02:00
Nathan Beals
2af36a3db4 Merge branch 'develop' of github.com:ndbeals/tandoor_recipes into develop 2022-04-23 00:11:08 -04:00
Nathan Beals
8df3009cb2 Update image upload handler to be content-type aware
Update handle_image: made filetype required and not optional
Updated handle_image usage to reflect changes
2022-04-23 00:11:04 -04:00
Kaibu
161ae9879a import app view refactor 2022-04-23 03:02:46 +02:00
vabene1111
71a60a46be Translated using Weblate (German)
Currently translated at 96.8% (372 of 384 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2022-04-23 00:54:22 +00:00
Kaibu
93acac1f3b Translated using Weblate (German)
Currently translated at 96.8% (372 of 384 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/de/
2022-04-23 00:54:22 +00:00
vabene1111
b4ebd98ee8 ingredient editor paginatio 2022-04-23 02:28:26 +02:00
vabene1111
78c0c5c213 ingredient editor improve merge/delete add edit 2022-04-23 02:17:40 +02:00
vabene1111
30d5587fbe added err msg to all standard toasts 2022-04-23 01:41:08 +02:00
vabene1111
e4223787be updated standard toast function 2022-04-23 01:31:15 +02:00
vabene1111
3850287deb WSL docs 2022-04-23 01:28:56 +02:00
Kaibu
7fae95e248 Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-04-23 01:28:25 +02:00
Kaibu
b037203b8f ui improvements (shopping and meal plan)
- fixed content scaling for meal plan and shopping
- style fixes on shopping list
- touch based swipe actions for shopping list
- better mobile experience overall
2022-04-23 01:28:20 +02:00
vabene1111
9b132e71f2 screw up ingredient parser 2022-04-23 01:21:13 +02:00
vabene1111
1a21659b5e Merge pull request #1737 from TandoorRecipes/dependabot/pip/django-3.2.13
Bump django from 3.2.12 to 3.2.13
2022-04-23 01:01:40 +02:00
dependabot[bot]
1a1dd092d0 Bump django from 3.2.12 to 3.2.13
Bumps [django](https://github.com/django/django) from 3.2.12 to 3.2.13.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.2.12...3.2.13)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-22 22:45:49 +00:00
vabene1111
9adc1f7266 small fixes and tests 2022-04-22 22:27:17 +02:00
vabene1111
6953f763d2 improved source url field rendering 2022-04-22 21:13:00 +02:00
vabene1111
4ecf77f431 Merge branch 'feature/importer_to_vue' into develop
# Conflicts:
#	vue/src/apps/RecipeView/RecipeView.vue
2022-04-22 21:07:02 +02:00
vabene1111
c4f5b160a6 show original text in recipe editor 2022-04-22 21:05:23 +02:00
vabene1111
d8f6dbc58f import list to textarea 2022-04-22 21:00:59 +02:00
vabene1111
8d3747a304 added missing doc entries 2022-04-22 20:30:05 +02:00
vabene1111
1740913a14 improve experience when importing multiple recipes 2022-04-22 20:19:39 +02:00
vabene1111
3cf0395a18 lots of small fixes 2022-04-22 19:26:49 +02:00
Kaibu
42dfc9d126 source url added 2022-04-22 18:53:23 +02:00
Kaibu
d7bd731c73 minor ui fix in recipe view 2022-04-22 17:43:23 +02:00
Kaibu
9e86abb004 Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-04-22 17:33:33 +02:00
Kaibu
dc8ce0f6a4 recipe image max-width based on ingredient table 2022-04-22 17:33:27 +02:00
vabene1111
2ddb0c719a Merge branch 'develop' into feature/importer_to_vue
# Conflicts:
#	vue/src/apps/RecipeEditView/RecipeEditView.vue
#	vue/src/utils/openapi/api.ts
2022-04-22 16:41:13 +02:00
Tomasz Klimczak
05383a2bc3 Translated using Weblate (Polish)
Currently translated at 100.0% (384 of 384 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-04-21 19:14:53 +00:00
Drumstickx
48c0252893 Fix link in German locale 2022-04-21 18:51:38 +02:00
Tomasz Klimczak
82fd6f1860 Translated using Weblate (Polish)
Currently translated at 100.0% (383 of 383 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-04-19 04:18:02 +00:00
Kaibu
694022506d Merge branch 'develop' of https://github.com/vabene1111/recipes into develop 2022-04-18 14:13:30 +02:00
Kaibu
45a86a22e3 recipe switcher and navbar fixes
also added left_hand to global preferences
2022-04-18 14:13:23 +02:00
vabene1111
1100826ed8 fixed NC importer importing empty keywords 2022-04-18 12:52:32 +02:00
vabene1111
d1065c8ac4 Merge pull request #1710 from hendrikbl/feature/navbar-tweaks
Navbar tweaks
2022-04-18 12:37:45 +02:00
vabene1111
2fdd9edde1 Merge pull request #1731 from parkroland/enhancement/clickable-keywords-recipe-card
Add clickable keywords to recipe card
2022-04-18 12:33:10 +02:00
Roland Park
a84ab0c049 Add clickable keywords to recipe card 2022-04-17 19:56:36 -04:00
vabene1111
d9dd0a594e show recipe and allow delete in ingredient editor 2022-04-17 23:25:22 +02:00
vabene1111
f0d59a8c9c added ability to open ingredient editor from food/unit list 2022-04-17 22:43:33 +02:00
vabene1111
d50fb69ce9 fixed errro message in meal plan when adding notes with add to shopping 2022-04-17 15:48:18 +02:00
vabene1111
8bc13fc91f fixed env template email settings 2022-04-17 15:35:41 +02:00
vabene1111
2ce06a8154 fixed too small fractions dissappearing 2022-04-17 15:35:32 +02:00
vabene1111
0a0c0b069f fixed space management page template error 2022-04-17 15:03:50 +02:00
vabene1111
47b62aa390 Merge pull request #1714 from gloriousDan/docs_nginx_read_only
Docs: nginx mount volumes read-only
2022-04-17 14:59:57 +02:00
vabene1111
9a2f91d3d4 Merge pull request #1709 from gloriousDan/develop
Docs: Reintroduce restart-always to web_recipes service
2022-04-17 14:58:55 +02:00
vabene1111
2df940ee40 improved rezkonv importer 2022-04-17 14:55:30 +02:00
Oskar Stenberg
67a5d8f1bd Translated using Weblate (Swedish)
Currently translated at 100.0% (371 of 371 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/sv/
2022-04-17 00:32:01 +00:00
vabene1111
297a8d4c8b ingredient editor basics done 2022-04-14 22:45:31 +02:00
vabene1111
976bce5fdd add merge capability to ingredient editor 2022-04-14 22:10:48 +02:00
vabene1111
8c89438b97 allow delete in ingredient editor 2022-04-14 14:40:15 +02:00
vabene1111
7ca7bd6111 improve generic form delete 2022-04-14 14:31:34 +02:00
Veit Kunz
095befd9b7 Fix some issues to improve the print output 2022-04-14 14:26:36 +02:00
vabene1111
3159868ba4 moved generic multiselect create function into component 2022-04-14 14:08:16 +02:00
vabene1111
7befa4a084 added basic ingredient editor 2022-04-14 13:01:27 +02:00
vabene1111
2ee96c2ea4 docs run on master, update contrib. docs 2022-04-14 08:53:16 +02:00
vabene1111
74b67e5549 Merge pull request #1719 from tristanlins/develop
Remove namespace vom k8s templates
2022-04-14 08:40:51 +02:00
vabene1111
1e24161d4c Merge pull request #1711 from Makanz/add-swedish-language-support
Add swedish language support
2022-04-14 08:39:29 +02:00
Tristan Lins
a839fb0bfc Remove namespace vom k8s templates 2022-04-12 20:43:58 +02:00
cesar ferreira
46267a135b Translated using Weblate (Portuguese)
Currently translated at 7.8% (30 of 381 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pt/
2022-04-12 18:32:03 +00:00
Tomasz Klimczak
f7ab0400a3 Translated using Weblate (Polish)
Currently translated at 100.0% (381 of 381 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-04-12 18:32:02 +00:00
Marcus Alsterfjord
74863117c5 Translated using Weblate (Swedish)
Currently translated at 100.0% (381 of 381 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sv/
2022-04-12 18:32:01 +00:00
Marcus Alsterfjord
e872272fbd Translated using Weblate (Swedish)
Currently translated at 100.0% (371 of 371 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/sv/
2022-04-12 18:32:00 +00:00
Daniel
9ae7d591cc Merge branch 'TandoorRecipes:develop' into docs_nginx_read_only 2022-04-10 20:46:46 +02:00
Daniel Schulz
c3c697f4a8 Mount all volumes in nginx read-only 2022-04-10 20:45:34 +02:00
Tomasz Klimczak
60e8b95593 Translated using Weblate (Polish)
Currently translated at 88.1% (336 of 381 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pl/
2022-04-10 09:51:32 +00:00
Marcus Alsterfjord
1636710099 Translated using Weblate (Swedish)
Currently translated at 61.7% (229 of 371 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/sv/
2022-04-10 09:51:31 +00:00
Rubens
4296c3d136 Translated using Weblate (Catalan)
Currently translated at 96.4% (542 of 562 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ca/
2022-04-10 09:51:31 +00:00
Marcus Alsterfjord
bcda5eea93 Update CONTRIBUTERS.md 2022-04-09 16:52:18 +02:00
Marcus Alsterfjord
a63ede0e3a Add swedish support in frontend ui and in search 2022-04-09 16:51:16 +02:00
hendrikbl
a9414065b5 changed navbar logo size and order 2022-04-09 16:15:10 +02:00
Daniel Schulz
fa79adf931 Reintroduce restart-always to web_recipes service 2022-04-09 14:56:00 +02:00
Marcus Alsterfjord
cd5f752d26 Translated using Weblate (Swedish)
Currently translated at 85.8% (327 of 381 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sv/
2022-04-08 22:32:07 +00:00
Rubens
6a41b182f5 Translated using Weblate (Catalan)
Currently translated at 79.8% (449 of 562 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ca/
2022-04-08 22:32:07 +00:00
vabene1111
0011ce26d3 Merge pull request #1705 from amillerr/patch-1
Update CONTRIBUTERS.md
2022-04-08 08:03:29 +02:00
Artem Aksenov
1ef92df83c Translated using Weblate (Russian)
Currently translated at 8.8% (44 of 496 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ru/
2022-04-07 19:32:01 +00:00
Artem Aksenov
3e8ef33402 Translated using Weblate (Russian)
Currently translated at 54.3% (207 of 381 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/ru/
2022-04-07 19:32:00 +00:00
Rubens
4d4c3bea92 Translated using Weblate (Catalan)
Currently translated at 56.5% (318 of 562 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/ca/
2022-04-07 19:32:00 +00:00
Artyom Aksyonov
9ecbfb0655 Update CONTRIBUTERS.md 2022-04-07 21:58:39 +03:00
Jesse
944492168e Translated using Weblate (Dutch)
Currently translated at 100.0% (378 of 378 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/nl/
2022-04-05 10:32:03 +00:00
Jesse
1c39befa0f Translated using Weblate (Dutch)
Currently translated at 100.0% (562 of 562 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/nl/
2022-04-05 10:32:03 +00:00
vabene1111
57ec6a2b3d import servings text 2022-04-04 23:21:13 +02:00
vabene1111
3653d6b911 added source url to nextcloud cookbook 2022-04-04 22:55:00 +02:00
Kaibu
82c2cc0f40 ui improvements 2022-04-04 22:53:26 +02:00
vabene1111
48e9f3f8a9 added cookmate importer 2022-04-04 22:49:50 +02:00
vabene1111
12865437d7 copy me that improvements 2022-04-04 21:44:51 +02:00
vabene1111
090e18e405 paprika importer improvements 2022-04-04 21:30:00 +02:00
vabene1111
7db49b1528 Merge pull request #1698 from HarHarLinks/patch-1
fix links in german locale
2022-04-04 21:16:06 +02:00
vabene1111
85aad42529 added mela recipes importer 2022-04-04 21:09:47 +02:00
Kim Brose
9c254be4b5 fix links in german locale 2022-04-04 20:34:01 +02:00
vabene1111
5bd9a15e4b small fixes 2022-04-04 20:11:22 +02:00
vabene1111
3cedab45ee fixed copy recipe nutrition link 2022-04-04 19:45:37 +02:00
vabene1111
56f3fe2d12 fixed deprecated model attribute on exporters 2022-04-04 19:27:14 +02:00
vabene1111
a2954554b5 fixed description length limit 2022-04-04 19:26:47 +02:00
vabene1111
528ada7d32 Merge branch 'develop' into feature/importer_to_vue
# Conflicts:
#	vue/package.json
2022-04-04 19:16:20 +02:00
vabene1111
b7e6e7b1b0 fixed s3 check 2022-04-04 19:15:11 +02:00
vabene1111
e17da08a74 Merge pull request #1679 from TandoorRecipes/dependabot/pip/jinja2-3.1.1
Bump jinja2 from 3.0.3 to 3.1.1
2022-04-04 19:07:34 +02:00
vabene1111
32cedf1078 Merge pull request #1680 from TandoorRecipes/dependabot/pip/boto3-1.21.31
Bump boto3 from 1.21.28 to 1.21.31
2022-04-04 19:07:29 +02:00
vabene1111
60bb3fd4aa Merge pull request #1633 from smilerz/recipe_as_food
allow marking recipe as food
2022-04-04 19:06:10 +02:00
dependabot[bot]
f421990ae0 Bump jinja2 from 3.0.3 to 3.1.1
Bumps [jinja2](https://github.com/pallets/jinja) from 3.0.3 to 3.1.1.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.0.3...3.1.1)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-04 17:05:40 +00:00
vabene1111
f9333d2b82 Merge pull request #1681 from TandoorRecipes/dependabot/pip/recipe-scrapers-13.25.0
Bump recipe-scrapers from 13.19.0 to 13.25.0
2022-04-04 19:04:58 +02:00
vabene1111
dfa5475ecb Merge pull request #1690 from kettenbach-it/develop
Get image from S3-storage if configured
2022-04-04 19:02:35 +02:00
Volker Kettenbach
b6e5425bd3 Get image from S3-Storage if configured 2022-04-02 11:35:35 +02:00
dependabot[bot]
1b7347f1d9 Bump recipe-scrapers from 13.19.0 to 13.25.0
Bumps [recipe-scrapers](https://github.com/hhursev/recipe-scrapers) from 13.19.0 to 13.25.0.
- [Release notes](https://github.com/hhursev/recipe-scrapers/releases)
- [Commits](https://github.com/hhursev/recipe-scrapers/compare/13.19.0...13.25.0)

---
updated-dependencies:
- dependency-name: recipe-scrapers
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-01 00:04:59 +00:00
dependabot[bot]
2ef23d2cb3 Bump boto3 from 1.21.28 to 1.21.31
Bumps [boto3](https://github.com/boto/boto3) from 1.21.28 to 1.21.31.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.21.28...1.21.31)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-01 00:04:51 +00:00
Lucas Declercq
bba81f6594 Translated using Weblate (French)
Currently translated at 87.3% (330 of 378 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fr/
2022-03-31 06:01:57 +00:00
Marcus Alsterfjord
3a4f08f2f7 Translated using Weblate (Swedish)
Currently translated at 57.6% (218 of 378 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sv/
2022-03-31 06:01:56 +00:00
Marcus Alsterfjord
f8ad465113 Translated using Weblate (Swedish)
Currently translated at 55.0% (208 of 378 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sv/
2022-03-29 20:36:24 +00:00
Marcus Alsterfjord
6df993ce29 Translated using Weblate (Swedish)
Currently translated at 54.7% (203 of 371 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/sv/
2022-03-29 20:36:24 +00:00
Adrian M
6009eae42d Translated using Weblate (Hungarian)
Currently translated at 100.0% (568 of 568 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/hu/
2022-03-29 20:36:24 +00:00
vabene1111
7bed9963ff fixed vue cli pwa version and admin comment search 2022-03-28 22:56:45 +02:00
vabene1111
a0610ac05f Merge pull request #1676 from TandoorRecipes/dependabot/npm_and_yarn/vue/vue/cli-plugin-eslint-5.0.4
Bump @vue/cli-plugin-eslint from 4.5.15 to 5.0.4 in /vue
2022-03-28 22:15:58 +02:00
dependabot[bot]
afd063a2b9 Bump @vue/cli-plugin-eslint from 4.5.15 to 5.0.4 in /vue
Bumps [@vue/cli-plugin-eslint](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-eslint) from 4.5.15 to 5.0.4.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v5.0.4/packages/@vue/cli-plugin-eslint)

---
updated-dependencies:
- dependency-name: "@vue/cli-plugin-eslint"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 20:01:08 +00:00
vabene1111
6b92dcbb2a Merge pull request #1606 from TandoorRecipes/dependabot/npm_and_yarn/vue/workbox-routing-6.5.0
Bump workbox-routing from 6.4.2 to 6.5.0 in /vue
2022-03-28 21:59:22 +02:00
vabene1111
12af99f546 Merge pull request #1668 from TandoorRecipes/dependabot/pip/cryptography-36.0.2
Bump cryptography from 36.0.1 to 36.0.2
2022-03-28 21:59:08 +02:00
vabene1111
68501d646d Merge pull request #1675 from TandoorRecipes/dependabot/npm_and_yarn/vue/axios-0.26.1
Bump axios from 0.24.0 to 0.26.1 in /vue
2022-03-28 21:58:52 +02:00
vabene1111
d215d236f0 Merge pull request #1669 from TandoorRecipes/dependabot/pip/boto3-1.21.28
Bump boto3 from 1.20.47 to 1.21.28
2022-03-28 21:58:41 +02:00
dependabot[bot]
459cf79ef3 Bump axios from 0.24.0 to 0.26.1 in /vue
Bumps [axios](https://github.com/axios/axios) from 0.24.0 to 0.26.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.24.0...v0.26.1)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:58:40 +00:00
dependabot[bot]
1d357eca4e Bump cryptography from 36.0.1 to 36.0.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 36.0.1 to 36.0.2.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/36.0.1...36.0.2)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:58:38 +00:00
vabene1111
ca8a7c3bc9 Merge pull request #1626 from TandoorRecipes/dependabot/pip/whitenoise-6.0.0
Bump whitenoise from 5.3.0 to 6.0.0
2022-03-28 21:58:30 +02:00
vabene1111
3b936eca3f Merge pull request #1674 from TandoorRecipes/dependabot/pip/python-dotenv-0.20.0
Bump python-dotenv from 0.19.2 to 0.20.0
2022-03-28 21:58:18 +02:00
vabene1111
2f06e9bc1c Merge pull request #1673 from TandoorRecipes/dependabot/pip/django-autocomplete-light-3.9.4
Bump django-autocomplete-light from 3.8.2 to 3.9.4
2022-03-28 21:57:25 +02:00
dependabot[bot]
e25c0705c6 Bump python-dotenv from 0.19.2 to 0.20.0
Bumps [python-dotenv](https://github.com/theskumar/python-dotenv) from 0.19.2 to 0.20.0.
- [Release notes](https://github.com/theskumar/python-dotenv/releases)
- [Changelog](https://github.com/theskumar/python-dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/theskumar/python-dotenv/compare/v0.19.2...v0.20.0)

---
updated-dependencies:
- dependency-name: python-dotenv
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:57:19 +00:00
vabene1111
d4e9526c75 Merge pull request #1670 from TandoorRecipes/dependabot/npm_and_yarn/vue/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6 in /vue
2022-03-28 21:56:52 +02:00
dependabot[bot]
2e2e81638b Bump django-autocomplete-light from 3.8.2 to 3.9.4
Bumps [django-autocomplete-light](https://github.com/yourlabs/django-autocomplete-light) from 3.8.2 to 3.9.4.
- [Release notes](https://github.com/yourlabs/django-autocomplete-light/releases)
- [Changelog](https://github.com/yourlabs/django-autocomplete-light/blob/master/CHANGELOG)
- [Commits](https://github.com/yourlabs/django-autocomplete-light/compare/3.8.2...3.9.4)

---
updated-dependencies:
- dependency-name: django-autocomplete-light
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:56:46 +00:00
vabene1111
baf5c9700f Merge pull request #1671 from TandoorRecipes/dependabot/pip/django-allauth-0.50.0
Bump django-allauth from 0.47.0 to 0.50.0
2022-03-28 21:56:39 +02:00
dependabot[bot]
dff7daefc7 Bump django-allauth from 0.47.0 to 0.50.0
Bumps [django-allauth](https://github.com/pennersr/django-allauth) from 0.47.0 to 0.50.0.
- [Release notes](https://github.com/pennersr/django-allauth/releases)
- [Changelog](https://github.com/pennersr/django-allauth/blob/master/ChangeLog.rst)
- [Commits](https://github.com/pennersr/django-allauth/compare/0.47.0...0.50.0)

---
updated-dependencies:
- dependency-name: django-allauth
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:56:33 +00:00
vabene1111
7e27d704ca Merge pull request #1672 from TandoorRecipes/dependabot/pip/pytest-7.1.1
Bump pytest from 7.0.1 to 7.1.1
2022-03-28 21:56:27 +02:00
vabene1111
9722f22837 Merge pull request #1604 from TandoorRecipes/dependabot/npm_and_yarn/vue/vue/cli-plugin-pwa-5.0.1
Bump @vue/cli-plugin-pwa from 4.5.15 to 5.0.1 in /vue
2022-03-28 21:56:09 +02:00
dependabot[bot]
707a12f8c1 Bump pytest from 7.0.1 to 7.1.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.0.1 to 7.1.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.0.1...7.1.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:55:38 +00:00
vabene1111
b9b8864631 Merge pull request #1603 from TandoorRecipes/dependabot/npm_and_yarn/vue/popperjs/core-2.11.2
Bump @popperjs/core from 2.11.0 to 2.11.2 in /vue
2022-03-28 21:55:37 +02:00
vabene1111
31bdc0589e Merge pull request #1602 from TandoorRecipes/dependabot/pip/lxml-4.8.0
Bump lxml from 4.7.1 to 4.8.0
2022-03-28 21:55:26 +02:00
dependabot[bot]
cb29caf88c Bump whitenoise from 5.3.0 to 6.0.0
Bumps [whitenoise](https://github.com/evansd/whitenoise) from 5.3.0 to 6.0.0.
- [Release notes](https://github.com/evansd/whitenoise/releases)
- [Changelog](https://github.com/evansd/whitenoise/blob/master/docs/changelog.rst)
- [Commits](https://github.com/evansd/whitenoise/compare/v5.3.0...6.0.0)

---
updated-dependencies:
- dependency-name: whitenoise
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:55:05 +00:00
dependabot[bot]
dd044eba36 Bump minimist from 1.2.5 to 1.2.6 in /vue
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:54:50 +00:00
dependabot[bot]
b8518884b0 Bump boto3 from 1.20.47 to 1.21.28
Bumps [boto3](https://github.com/boto/boto3) from 1.20.47 to 1.21.28.
- [Release notes](https://github.com/boto/boto3/releases)
- [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/boto/boto3/compare/1.20.47...1.21.28)

---
updated-dependencies:
- dependency-name: boto3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 19:54:47 +00:00
vabene1111
ed20a54137 Merge pull request #1601 from TandoorRecipes/dependabot/pip/django-allauth-0.49.0
Bump django-allauth from 0.47.0 to 0.49.0
2022-03-28 21:54:30 +02:00
vabene1111
7781bf1444 Merge pull request #1598 from TandoorRecipes/dependabot/pip/pytest-7.0.1
Bump pytest from 6.2.5 to 7.0.1
2022-03-28 21:54:16 +02:00
vabene1111
14db4179b9 Merge pull request #1660 from MaxJa4/patch-1
Add POSTGRES_USER to psql health check during boot
2022-03-28 21:53:27 +02:00
Adrian M
37eab3ece2 Translated using Weblate (Hungarian)
Currently translated at 57.3% (326 of 568 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/hu/
2022-03-28 01:56:10 +00:00
Adrian M
768b483351 Translated using Weblate (Hungarian)
Currently translated at 12.1% (69 of 568 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/hu/
2022-03-27 18:00:28 +00:00
MaxJa4
59d277da3d Add POSTGRES_USER to psql health check during boot
Add POSTGRES_USER to psql health check during boot to support external psql instances better.

Fixes #1656
2022-03-20 00:08:41 +01:00
Stefan Werner
f68fd0fa94 Translated using Weblate (Finnish)
Currently translated at 56.3% (213 of 378 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/fi/
2022-03-18 16:31:49 +00:00
Stefan Werner
dd1fcc21e0 Translated using Weblate (Finnish)
Currently translated at 3.2% (16 of 493 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/fi/
2022-03-18 16:31:49 +00:00
vabene1111
f445722140 Merge pull request #1653 from bradpoulton/develop
Fixes the formatting
2022-03-17 20:46:41 +01:00
brad
a3def6bf4c Fixes the formatting 2022-03-16 22:00:42 -06:00
Adrian M
cbd2ac2032 Translated using Weblate (Hungarian)
Currently translated at 5.6% (32 of 568 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/hu/
2022-03-16 22:31:47 +00:00
vabene1111
1d3d4e78f5 Merge branch 'develop' 2022-03-16 14:27:11 +01:00
vabene1111
0c841ec686 another improvement to shopping list item 2022-03-16 09:21:09 +01:00
ivo
f875942e79 Translated using Weblate (Portuguese)
Currently translated at 1.0% (4 of 378 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/pt/
2022-03-15 19:31:47 +00:00
vabene1111
e901c6708c Merge branch 'develop' into feature/importer_to_vue 2022-03-15 13:02:10 +01:00
vabene1111
c5863a5309 Merge branch 'develop' 2022-03-15 13:01:59 +01:00
vabene1111
7426bb4e76 auto import multiple urls 2022-03-10 17:35:11 +01:00
vabene1111
92b536b32c check login remember by default 2022-03-10 16:10:33 +01:00
vabene1111
5627161c5e Merge branch 'develop' into feature/importer_to_vue 2022-03-10 15:27:11 +01:00
smilerz
486d197854 allow marking recipe as food 2022-03-06 23:12:59 -06:00
vabene1111
22ca482458 super very basics of manual mapping page working 2022-03-05 16:02:42 +01:00
vabene1111
2565ab30a4 lots of improvements and bookmarklet import working again 2022-03-05 15:16:58 +01:00
vabene1111
1caabef56a step functions 2022-03-04 16:54:59 +01:00
vabene1111
edde8c8b8f Merge branch 'develop' 2022-03-04 15:54:16 +01:00
vabene1111
6d8fe3c162 wip 2022-03-04 15:54:11 +01:00
vabene1111
bdccdf0893 Merge branch 'develop' into feature/importer_to_vue
# Conflicts:
#	cookbook/helper/recipe_url_import.py
2022-03-04 14:33:59 +01:00
dependabot[bot]
f0927bf065 Bump django-allauth from 0.47.0 to 0.49.0
Bumps [django-allauth](https://github.com/pennersr/django-allauth) from 0.47.0 to 0.49.0.
- [Release notes](https://github.com/pennersr/django-allauth/releases)
- [Changelog](https://github.com/pennersr/django-allauth/blob/master/ChangeLog.rst)
- [Commits](https://github.com/pennersr/django-allauth/compare/0.47.0...0.49.0)

---
updated-dependencies:
- dependency-name: django-allauth
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-04 13:30:25 +00:00
dependabot[bot]
ed1fb9a95e Bump pytest from 6.2.5 to 7.0.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.5 to 7.0.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.2.5...7.0.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-04 13:30:07 +00:00
vabene1111
030d977a8c Merge branch 'develop' 2022-03-02 13:11:57 +01:00
dependabot[bot]
5f25df7d19 Bump workbox-routing from 6.4.2 to 6.5.0 in /vue
Bumps [workbox-routing](https://github.com/googlechrome/workbox) from 6.4.2 to 6.5.0.
- [Release notes](https://github.com/googlechrome/workbox/releases)
- [Commits](https://github.com/googlechrome/workbox/compare/v6.4.2...v6.5.0)

---
updated-dependencies:
- dependency-name: workbox-routing
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-01 00:12:01 +00:00
dependabot[bot]
e55f78c767 Bump @vue/cli-plugin-pwa from 4.5.15 to 5.0.1 in /vue
Bumps [@vue/cli-plugin-pwa](https://github.com/vuejs/vue-cli/tree/HEAD/packages/@vue/cli-plugin-pwa) from 4.5.15 to 5.0.1.
- [Release notes](https://github.com/vuejs/vue-cli/releases)
- [Changelog](https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/vuejs/vue-cli/commits/v5.0.1/packages/@vue/cli-plugin-pwa)

---
updated-dependencies:
- dependency-name: "@vue/cli-plugin-pwa"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-01 00:10:36 +00:00
dependabot[bot]
6d257d2455 Bump @popperjs/core from 2.11.0 to 2.11.2 in /vue
Bumps [@popperjs/core](https://github.com/popperjs/popper-core) from 2.11.0 to 2.11.2.
- [Release notes](https://github.com/popperjs/popper-core/releases)
- [Commits](https://github.com/popperjs/popper-core/compare/v2.11.0...v2.11.2)

---
updated-dependencies:
- dependency-name: "@popperjs/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-01 00:09:44 +00:00
dependabot[bot]
693a5214ef Bump lxml from 4.7.1 to 4.8.0
Bumps [lxml](https://github.com/lxml/lxml) from 4.7.1 to 4.8.0.
- [Release notes](https://github.com/lxml/lxml/releases)
- [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt)
- [Commits](https://github.com/lxml/lxml/compare/lxml-4.7.1...lxml-4.8.0)

---
updated-dependencies:
- dependency-name: lxml
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-01 00:03:39 +00:00
vabene1111
52c16ab7dd all types bascially working (lacking bookmark) 2022-02-22 17:00:30 +01:00
vabene1111
0d98c77301 some small ui stuff 2022-02-21 18:29:23 +01:00
vabene1111
e04d672750 import with image working 2022-02-21 15:59:30 +01:00
vabene1111
c06c511dc9 changed unit default in ingredient parser to none
because empty name units are not accepted by unit serializer but null values can be handled by the ingredient serializer (as a unit can be null)
2022-02-21 15:35:36 +01:00
nough
0ae1ecd867 Update backup.md
Added manual backup method first draft
2022-02-20 00:59:56 +00:00
vabene1111
c8fc67fa2b changed source import to match field structure of recipe model
first imports working
2022-02-19 17:54:00 +01:00
vabene1111
89348f69f1 basics of new import page 2022-02-19 16:55:17 +01:00
vabene1111
55b035eaaa first boilerplate for new import view 2022-02-19 09:34:42 +01:00
276 changed files with 48872 additions and 38563 deletions

View File

@@ -86,8 +86,10 @@ GUNICORN_MEDIA=0
# EMAIL_HOST_PASSWORD=
# EMAIL_USE_TLS=0
# EMAIL_USE_SSL=0
# DEFAULT_FROM_EMAIL= # email sender address (default 'webmaster@localhost')
# ACCOUNT_EMAIL_SUBJECT_PREFIX= # prefix used for account related emails (default "[Tandoor Recipes] ")
# email sender address (default 'webmaster@localhost')
# DEFAULT_FROM_EMAIL=
# prefix used for account related emails (default "[Tandoor Recipes] ")
# ACCOUNT_EMAIL_SUBJECT_PREFIX=
# allow authentication via reverse proxy (e.g. authelia), leave off if you dont know what you are doing
# see docs for more information https://vabene1111.github.io/recipes/features/authentication/

View File

@@ -29,6 +29,7 @@ jobs:
run: yarn build
- name: Install Django dependencies
run: |
sudo apt-get -y update
sudo apt-get install -y libsasl2-dev python-dev libldap2-dev libssl-dev
python -m pip install --upgrade pip
pip install -r requirements.txt

View File

@@ -0,0 +1,48 @@
name: publish beta raspi image docker
on:
push:
branches:
- 'beta'
jobs:
build:
if: github.repository_owner == 'TandoorRecipes'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
# Update Version number
- name: Update version file
uses: DamianReeves/write-file-action@v1.0
with:
path: recipes/version.py
contents: |
VERSION_NUMBER = 'beta'
BUILD_REF = '${{ github.sha }}'
write-mode: overwrite
# Build Vue frontend
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Install dependencies
working-directory: ./vue
run: yarn install
- name: Build dependencies
working-directory: ./vue
run: yarn build
# Build container
- name: Build and publish image
uses: ilteoood/docker_buildx@master
with:
publish: true
imageName: vabene1111/recipes
tag: beta-raspi
dockerFile: Dockerfile-raspi
platform: linux/arm/v7
dockerUser: ${{ secrets.DOCKER_USERNAME }}
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}
# Send discord notification
- name: Discord notification
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_BETA_WEBHOOK }}
uses: Ilshidur/action-discord@0.3.2
with:
args: '🚀 The BETA Image has been updated! 🥳'

View File

@@ -35,6 +35,7 @@ jobs:
publish: true
imageName: vabene1111/recipes
tag: beta
platform: linux/amd64,linux/arm64
dockerUser: ${{ secrets.DOCKER_USERNAME }}
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}
# Send discord notification

View File

@@ -0,0 +1,45 @@
name: publish latest raspi image docker
on:
push:
tags:
- '*'
jobs:
build:
if: github.repository_owner == 'TandoorRecipes'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Get version number
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}-raspi
# Update Version number
- name: Update version file
uses: DamianReeves/write-file-action@v1.0
with:
path: recipes/version.py
contents: |
VERSION_NUMBER = '${{ steps.get_version.outputs.VERSION }}-raspi'
BUILD_REF = '${{ github.sha }}'
write-mode: overwrite
# Build Vue frontend
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Install dependencies
working-directory: ./vue
run: yarn install
- name: Build dependencies
working-directory: ./vue
run: yarn build
# Build container
- name: Build and publish image
uses: ilteoood/docker_buildx@master
with:
publish: true
imageName: vabene1111/recipes
dockerFile: Dockerfile-raspi
platform: linux/arm/v7
tag: latest-raspi
dockerUser: ${{ secrets.DOCKER_USERNAME }}
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -38,6 +38,7 @@ jobs:
with:
publish: true
imageName: vabene1111/recipes
platform: linux/amd64,linux/arm64
tag: latest
dockerUser: ${{ secrets.DOCKER_USERNAME }}
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -0,0 +1,47 @@
name: publish tagged raspi release docker
on:
release:
types: [published]
jobs:
build:
if: github.repository_owner == 'TandoorRecipes'
runs-on: ubuntu-latest
name: Build image job
steps:
- name: Checkout master
uses: actions/checkout@master
- name: Get version number
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
# Update Version number
- name: Update version file
uses: DamianReeves/write-file-action@v1.0
with:
path: recipes/version.py
contents: |
VERSION_NUMBER = '${{ steps.get_version.outputs.VERSION }}'
BUILD_REF = '${{ github.sha }}'
write-mode: overwrite
# Build Vue frontend
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Install dependencies
working-directory: ./vue
run: yarn install
- name: Build dependencies
working-directory: ./vue
run: yarn build
# Build container
- name: Build and publish image
uses: ilteoood/docker_buildx@master
with:
publish: true
imageName: vabene1111/recipes
dockerFile: Dockerfile-raspi
platform: linux/arm/v7
tag: ${{ steps.get_version.outputs.VERSION }}-raspi
dockerUser: ${{ secrets.DOCKER_USERNAME }}
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -40,6 +40,7 @@ jobs:
with:
publish: true
imageName: vabene1111/recipes
platform: linux/amd64,linux/arm64
tag: ${{ steps.get_version.outputs.VERSION }}
dockerUser: ${{ secrets.DOCKER_USERNAME }}
dockerPassword: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -3,7 +3,6 @@ on:
push:
branches:
- master
- develop
jobs:
deploy:

View File

@@ -6,6 +6,7 @@
<w>csrftoken</w>
<w>gunicorn</w>
<w>ical</w>
<w>invitelink</w>
<w>mealie</w>
<w>pepperplate</w>
<w>safron</w>

View File

@@ -1,7 +1,10 @@
# Contributers
Many thanks to everyone who contributed to this project! If you add something or help out feel free to add yourself
to this list.
## Code/Features
Please have a look at the [list of pull requests](https://github.com/vabene1111/recipes/pulls) for
a complete list of contributions.
Below are some of the larger contributions made yet.
@@ -20,46 +23,61 @@ Below are some of the larger contributions made yet.
## Translations
### Catalan
### Catalan
[Rubenix](https://www.transifex.com/user/profile/rubenix/)
### Dutch
[D0T1X](https://www.transifex.com/user/profile/D0T1X/)
[ikbenfrank](https://www.transifex.com/user/profile/ikbenfrank/)
[kampsj](https://www.transifex.com/user/profile/kampsj/)
[D0T1X](https://www.transifex.com/user/profile/D0T1X/)
[ikbenfrank](https://www.transifex.com/user/profile/ikbenfrank/)
[kampsj](https://www.transifex.com/user/profile/kampsj/)
### French
[jt117](https://www.transifex.com/user/profile/jt117/)
[nerdinator](https://www.transifex.com/user/profile/nerdinator/)
[agaume](https://www.transifex.com/user/profile/agaume/)
[jt117](https://www.transifex.com/user/profile/jt117/)
[nerdinator](https://www.transifex.com/user/profile/nerdinator/)
[agaume](https://www.transifex.com/user/profile/agaume/)
### German
[eTaurus](https://www.transifex.com/user/profile/eTaurus/)
[l0c4lh057](https://www.transifex.com/user/profile/l0c4lh057/)
[hyperbit00]
[hyperbit00](https://github.com/hyperbit00)
### Hungarian
[igazka](https://www.transifex.com/user/profile/igazka/)
### Italian
[SK3LA](https://www.transifex.com/user/profile/SK3LA/)
[auanasgheps](https://www.transifex.com/user/profile/auanasgheps/)
[SK3LA](https://www.transifex.com/user/profile/SK3LA/)
[auanasgheps](https://www.transifex.com/user/profile/auanasgheps/)
### Latvian
[melkypie](https://github.com/melkypie)
### Portuguese
[hds](https://www.transifex.com/user/profile/hds/)
[mlopezifu](https://www.transifex.com/user/profile/mlopezifu/)
[stormsz](https://www.transifex.com/user/profile/stormsz/)
[hds](https://www.transifex.com/user/profile/hds/)
[mlopezifu](https://www.transifex.com/user/profile/mlopezifu/)
[stormsz](https://www.transifex.com/user/profile/stormsz/)
### Russian
[amillerr](https://github.com/amillerr)
### Spanish
[albertocp](https://www.transifex.com/user/profile/albertocp/)
[alfa5](https://www.transifex.com/user/profile/alfa5/)
[mlopezifu](https://www.transifex.com/user/profile/mlopezifu/)
[sergio.laya](https://www.transifex.com/user/profile/sergio.laya/)
[albertocp](https://www.transifex.com/user/profile/albertocp/)
[alfa5](https://www.transifex.com/user/profile/alfa5/)
[mlopezifu](https://www.transifex.com/user/profile/mlopezifu/)
[sergio.laya](https://www.transifex.com/user/profile/sergio.laya/)
### Swedish
[makanz](https://github.com/makanz)
### Turkish

View File

@@ -15,7 +15,7 @@ WORKDIR /opt/recipes
COPY requirements.txt ./
RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-dev jpeg-dev libwebp-dev libressl-dev libffi-dev cargo openssl-dev openldap-dev python3-dev && \
RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-dev jpeg-dev libwebp-dev openssl-dev libffi-dev cargo openldap-dev python3-dev git && \
echo -n "INPUT ( libldap.so )" > /usr/lib/libldap_r.so && \
python -m venv venv && \
/opt/recipes/venv/bin/python -m pip install --upgrade pip && \

33
Dockerfile-raspi Normal file
View File

@@ -0,0 +1,33 @@
# builds of cryptography for raspberry pi (or better arm v7) fail for some
FROM python:3.9-alpine3.15
#Install all dependencies.
RUN apk add --no-cache postgresql-libs postgresql-client gettext zlib libjpeg libwebp libxml2-dev libxslt-dev py-cryptography openldap gcompat
#Print all logs without buffering it.
ENV PYTHONUNBUFFERED 1
#This port will be used by gunicorn.
EXPOSE 8080
#Create app dir and install requirements.
RUN mkdir /opt/recipes
WORKDIR /opt/recipes
COPY requirements.txt ./
RUN \
if [ `apk --print-arch` = "armv7" ]; then \
printf "[global]\nextra-index-url=https://www.piwheels.org/simple\n" > /etc/pip.conf ; \
fi
RUN apk add --no-cache --virtual .build-deps gcc musl-dev zlib-dev jpeg-dev libwebp-dev python3-dev git && \
echo -n "INPUT ( libldap.so )" > /usr/lib/libldap_r.so && \
python -m venv venv && \
/opt/recipes/venv/bin/python -m pip install --upgrade pip && \
venv/bin/pip install wheel==0.37.1 && \
venv/bin/pip install -r requirements.txt --no-cache-dir --no-binary=Pillow && \
apk --purge del .build-deps
#Copy project and execute it.
COPY . ./
RUN chmod +x boot.sh
ENTRYPOINT ["/opt/recipes/boot.sh"]

View File

@@ -61,6 +61,15 @@ a public page.
Documentation can be found [here](https://docs.tandoor.dev/).
## Support our work
Tandoor is developed by volunteers in their free time just because its fun. That said earning
some money with the project allows us to spend more time on it and thus make improvements we otherwise couldn't.
Because of that there are several ways you can support us
- **GitHub Sponsors** You can sponsor contributors of this project on GitHub: [vabene1111](https://github.com/sponsors/vabene1111)
- **Host at Hetzner** We have been very happy customers of Hetzner for multiple years for all of our projects. If you want to get into self-hosting or are tired of the expensive big providers, their cloud servers are a great place to get started. When you sign up via our [referral link](https://hetzner.cloud/?ref=ISdlrLmr9kGj) you will get 20€ worth of cloud credits and we get a small kickback too.
- **Let us host for you** We are offering a [hosted version](https://app.tandoor.dev) where all profits support us and the development of tandoor (currently only available in germany).
## Contributing
You can help out with the ongoing development by looking for potential bugs in our code base, or by contributing new features. We are always welcoming new pull requests containing bug fixes, refactors and new features. We have a list of tasks and bugs on our issue tracker on Github. Please comment on issues if you want to contribute with, to avoid duplicating effort.

View File

@@ -34,7 +34,7 @@ if [ "${DB_ENGINE}" != 'django.db.backends.sqlite3' ]; then
display_warning "The environment variable 'POSTGRES_PASSWORD' is not set but REQUIRED for running Tandoor!"
fi
while pg_isready --host=${POSTGRES_HOST} --port=${POSTGRES_PORT} -q; status=$?; attempt=$((attempt+1)); [ $status -ne 0 ] && [ $attempt -le $max_attempts ]; do
while pg_isready --host=${POSTGRES_HOST} --port=${POSTGRES_PORT} --user=${POSTGRES_USER} -q; status=$?; attempt=$((attempt+1)); [ $status -ne 0 ] && [ $attempt -le $max_attempts ]; do
sleep 5
done
fi

View File

@@ -15,7 +15,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink,
ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog,
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation)
TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation, UserSpace)
class CustomUserAdmin(UserAdmin):
@@ -32,41 +32,7 @@ admin.site.unregister(Group)
@admin.action(description='Delete all data from a space')
def delete_space_action(modeladmin, request, queryset):
for space in queryset:
CookLog.objects.filter(space=space).delete()
ViewLog.objects.filter(space=space).delete()
ImportLog.objects.filter(space=space).delete()
BookmarkletImport.objects.filter(space=space).delete()
Comment.objects.filter(recipe__space=space).delete()
Keyword.objects.filter(space=space).delete()
Ingredient.objects.filter(space=space).delete()
Food.objects.filter(space=space).delete()
Unit.objects.filter(space=space).delete()
Step.objects.filter(space=space).delete()
NutritionInformation.objects.filter(space=space).delete()
RecipeBookEntry.objects.filter(book__space=space).delete()
RecipeBook.objects.filter(space=space).delete()
MealType.objects.filter(space=space).delete()
MealPlan.objects.filter(space=space).delete()
ShareLink.objects.filter(space=space).delete()
Recipe.objects.filter(space=space).delete()
RecipeImport.objects.filter(space=space).delete()
SyncLog.objects.filter(sync__space=space).delete()
Sync.objects.filter(space=space).delete()
Storage.objects.filter(space=space).delete()
ShoppingListEntry.objects.filter(shoppinglist__space=space).delete()
ShoppingListRecipe.objects.filter(shoppinglist__space=space).delete()
ShoppingList.objects.filter(space=space).delete()
SupermarketCategoryRelation.objects.filter(supermarket__space=space).delete()
SupermarketCategory.objects.filter(space=space).delete()
Supermarket.objects.filter(space=space).delete()
InviteLink.objects.filter(space=space).delete()
UserFile.objects.filter(space=space).delete()
Automation.objects.filter(space=space).delete()
space.save()
class SpaceAdmin(admin.ModelAdmin):
@@ -80,9 +46,17 @@ class SpaceAdmin(admin.ModelAdmin):
admin.site.register(Space, SpaceAdmin)
class UserSpaceAdmin(admin.ModelAdmin):
list_display = ('user', 'space',)
search_fields = ('user', 'space',)
admin.site.register(UserSpace, UserSpaceAdmin)
class UserPreferenceAdmin(admin.ModelAdmin):
list_display = ('name', 'space', 'theme', 'nav_color', 'default_page', 'search_style',) # TODO add new fields
search_fields = ('user__username', 'space__name')
list_display = ('name', 'theme', 'nav_color', 'default_page', 'search_style',) # TODO add new fields
search_fields = ('user__username',)
list_filter = ('theme', 'nav_color', 'default_page', 'search_style')
date_hierarchy = 'created_at'
@@ -237,7 +211,7 @@ admin.site.register(Ingredient, IngredientAdmin)
class CommentAdmin(admin.ModelAdmin):
list_display = ('recipe', 'name', 'created_at')
search_fields = ('text', 'user__username')
search_fields = ('text', 'created_by__username')
date_hierarchy = 'created_at'
@staticmethod

View File

@@ -6,7 +6,7 @@ from django.utils.translation import gettext as _
from django_scopes import scopes_disabled
from cookbook.forms import MultiSelectWidget
from cookbook.models import Food, Keyword, Recipe, ShoppingList
from cookbook.models import Food, Keyword, Recipe
with scopes_disabled():
class RecipeFilter(django_filters.FilterSet):
@@ -60,22 +60,3 @@ with scopes_disabled():
class Meta:
model = Recipe
fields = ['name', 'keywords', 'foods', 'internal']
# class FoodFilter(django_filters.FilterSet):
# name = django_filters.CharFilter(lookup_expr='icontains')
# class Meta:
# model = Food
# fields = ['name']
class ShoppingListFilter(django_filters.FilterSet):
def __init__(self, data=None, *args, **kwargs):
if data is not None:
data = data.copy()
data.setdefault("finished", False)
super().__init__(data, *args, **kwargs)
class Meta:
model = ShoppingList
fields = ['finished']

View File

@@ -37,19 +37,16 @@ class UserPreferenceForm(forms.ModelForm):
prefix = 'preference'
def __init__(self, *args, **kwargs):
if x := kwargs.get('instance', None):
space = x.space
else:
space = kwargs.pop('space')
space = kwargs.pop('space')
super().__init__(*args, **kwargs)
self.fields['plan_share'].queryset = User.objects.filter(userpreference__space=space).all()
self.fields['plan_share'].queryset = User.objects.filter(userspace__space=space).all()
class Meta:
model = UserPreference
fields = (
'default_unit', 'use_fractions', 'use_kj', 'theme', 'nav_color',
'sticky_navbar', 'default_page', 'show_recent', 'search_style',
'plan_share', 'ingredient_decimals', 'comments',
'plan_share', 'ingredient_decimals', 'comments', 'left_handed',
)
labels = {
@@ -65,7 +62,8 @@ class UserPreferenceForm(forms.ModelForm):
'plan_share': _('Plan sharing'),
'ingredient_decimals': _('Ingredient decimal places'),
'shopping_auto_sync': _('Shopping list auto sync period'),
'comments': _('Comments')
'comments': _('Comments'),
'left_handed': _('Left-handed mode')
}
help_texts = {
@@ -89,6 +87,7 @@ class UserPreferenceForm(forms.ModelForm):
'sticky_navbar': _('Makes the navbar stick to the top of the page.'), # noqa: E501
'mealplan_autoadd_shopping': _('Automatically add meal plan ingredients to shopping list.'),
'mealplan_autoexclude_onhand': _('Exclude ingredients that are on hand.'),
'left_handed': _('Will optimize the UI for use with your left hand.')
}
widgets = {
@@ -153,11 +152,13 @@ class ImportExportBase(forms.Form):
RECIPESAGE = 'RECIPESAGE'
DOMESTICA = 'DOMESTICA'
MEALMASTER = 'MEALMASTER'
MELARECIPES = 'MELARECIPES'
REZKONV = 'REZKONV'
OPENEATS = 'OPENEATS'
PLANTOEAT = 'PLANTOEAT'
COOKBOOKAPP = 'COOKBOOKAPP'
COPYMETHAT = 'COPYMETHAT'
COOKMATE = 'COOKMATE'
PDF = 'PDF'
type = forms.ChoiceField(choices=(
@@ -165,7 +166,8 @@ class ImportExportBase(forms.Form):
(MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFFRON, 'Saffron'), (CHEFTAP, 'ChefTap'),
(PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'),
(MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'),
(PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), (PDF, 'PDF'),
(PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), (PDF, 'PDF'), (MELARECIPES, 'Melarecipes'),
(COOKMATE, 'Cookmate')
))

View File

@@ -38,10 +38,12 @@ def get_filetype(name):
# TODO this whole file needs proper documentation, refactoring, and testing
# TODO also add env variable to define which images sizes should be compressed
def handle_image(request, image_object, filetype='.jpeg'):
# filetype argument can not be optional, otherwise this function will treat all images as if they were a jpeg
# Because it's no longer optional, no reason to return it
def handle_image(request, image_object, filetype):
if (image_object.size / 1000) > 500: # if larger than 500 kb compress
if filetype == '.jpeg' or filetype == '.jpg':
return rescale_image_jpeg(image_object), filetype
return rescale_image_jpeg(image_object)
if filetype == '.png':
return rescale_image_png(image_object), filetype
return image_object, filetype
return rescale_image_png(image_object)
return image_object

View File

@@ -4,7 +4,7 @@ import unicodedata
from django.core.cache import caches
from cookbook.models import Unit, Food, Automation
from cookbook.models import Unit, Food, Automation, Ingredient
class IngredientParser:
@@ -46,7 +46,7 @@ class IngredientParser:
def apply_food_automation(self, food):
"""
Apply food alias automations to passed foood
Apply food alias automations to passed food
:param food: unit as string
:return: food as string (possibly changed by automation)
"""
@@ -124,7 +124,7 @@ class IngredientParser:
def parse_amount(self, x):
amount = 0
unit = ''
unit = None
note = ''
did_check_frac = False
@@ -155,33 +155,36 @@ class IngredientParser:
except ValueError:
unit = x[end:]
if unit.startswith('(') or unit.startswith('-'): # i dont know any unit that starts with ( or - so its likely an alternative like 1L (500ml) Water or 2-3
unit = ''
if unit is not None and unit.strip() == '':
unit = None
if unit is not None and (unit.startswith('(') or unit.startswith('-')): # i dont know any unit that starts with ( or - so its likely an alternative like 1L (500ml) Water or 2-3
unit = None
note = x
return amount, unit, note
def parse_ingredient_with_comma(self, tokens):
ingredient = ''
def parse_food_with_comma(self, tokens):
food = ''
note = ''
start = 0
# search for first occurrence of an argument ending in a comma
while start < len(tokens) and not tokens[start].endswith(','):
start += 1
if start == len(tokens):
# no token ending in a comma found -> use everything as ingredient
ingredient = ' '.join(tokens)
# no token ending in a comma found -> use everything as food
food = ' '.join(tokens)
else:
ingredient = ' '.join(tokens[:start + 1])[:-1]
food = ' '.join(tokens[:start + 1])[:-1]
note = ' '.join(tokens[start + 1:])
return ingredient, note
return food, note
def parse_ingredient(self, tokens):
ingredient = ''
def parse_food(self, tokens):
food = ''
note = ''
if tokens[-1].endswith(')'):
# Check if the matching opening bracket is in the same token
if (not tokens[-1].startswith('(')) and ('(' in tokens[-1]):
return self.parse_ingredient_with_comma(tokens)
return self.parse_food_with_comma(tokens)
# last argument ends with closing bracket -> look for opening bracket
start = len(tokens) - 1
while not tokens[start].startswith('(') and not start == 0:
@@ -191,33 +194,51 @@ class IngredientParser:
raise ValueError
elif start < 0:
# no opening bracket anywhere -> just ignore the last bracket
ingredient, note = self.parse_ingredient_with_comma(tokens)
food, note = self.parse_food_with_comma(tokens)
else:
# opening bracket found -> split in ingredient and note, remove brackets from note # noqa: E501
# opening bracket found -> split in food and note, remove brackets from note # noqa: E501
note = ' '.join(tokens[start:])[1:-1]
ingredient = ' '.join(tokens[:start])
food = ' '.join(tokens[:start])
else:
ingredient, note = self.parse_ingredient_with_comma(tokens)
return ingredient, note
food, note = self.parse_food_with_comma(tokens)
return food, note
def parse(self, x):
def parse(self, ingredient):
"""
Main parsing function, takes an ingredient string (e.g. '1 l Water') and extracts amount, unit, food, ...
:param ingredient: string ingredient
:return: amount, unit (can be None), food, note (can be empty)
"""
# initialize default values
amount = 0
unit = ''
ingredient = ''
unit = None
food = ''
note = ''
unit_note = ''
if len(ingredient) == 0:
raise ValueError('string to parse cannot be empty')
# some people/languages put amount and unit at the end of the ingredient string
# if something like this is detected move it to the beginning so the parser can handle it
if len(ingredient) < 1000 and re.search(r'^([A-z])+(.)*[1-9](\d)*\s([A-z])+', ingredient):
match = re.search(r'[1-9](\d)*\s([A-z])+', ingredient)
print(f'reording from {ingredient} to {ingredient[match.start():match.end()] + " " + ingredient.replace(ingredient[match.start():match.end()], "")}')
ingredient = ingredient[match.start():match.end()] + ' ' + ingredient.replace(ingredient[match.start():match.end()], '')
# if the string contains parenthesis early on remove it and place it at the end
# because its likely some kind of note
if re.match('(.){1,6}\s\((.[^\(\)])+\)\s', x):
match = re.search('\((.[^\(])+\)', x)
x = x[:match.start()] + x[match.end():] + ' ' + x[match.start():match.end()]
if re.match('(.){1,6}\s\((.[^\(\)])+\)\s', ingredient):
match = re.search('\((.[^\(])+\)', ingredient)
ingredient = ingredient[:match.start()] + ingredient[match.end():] + ' ' + ingredient[match.start():match.end()]
tokens = x.split()
# leading spaces before commas result in extra tokens, clean them out
ingredient = ingredient.replace(' ,', ',')
tokens = ingredient.split() # split at each space into tokens
if len(tokens) == 1:
# there only is one argument, that must be the ingredient
ingredient = tokens[0]
# there only is one argument, that must be the food
food = tokens[0]
else:
try:
# try to parse first argument as amount
@@ -227,48 +248,65 @@ class IngredientParser:
# a fraction for the amount
if len(tokens) > 2:
try:
if not unit == '':
if unit is not None:
# a unit is already found, no need to try the second argument for a fraction
# probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except # noqa: E501
# probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except
raise ValueError
# try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½'
amount += self.parse_fraction(tokens[1])
# assume that units can't end with a comma
if len(tokens) > 3 and not tokens[2].endswith(','):
# try to use third argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
# try to use third argument as unit and everything else as food, use everything as food if it fails
try:
ingredient, note = self.parse_ingredient(tokens[3:])
food, note = self.parse_food(tokens[3:])
unit = tokens[2]
except ValueError:
ingredient, note = self.parse_ingredient(tokens[2:])
food, note = self.parse_food(tokens[2:])
else:
ingredient, note = self.parse_ingredient(tokens[2:])
food, note = self.parse_food(tokens[2:])
except ValueError:
# assume that units can't end with a comma
if not tokens[1].endswith(','):
# try to use second argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
# try to use second argument as unit and everything else as food, use everything as food if it fails
try:
ingredient, note = self.parse_ingredient(tokens[2:])
if unit == '':
food, note = self.parse_food(tokens[2:])
if unit is None:
unit = tokens[1]
else:
note = tokens[1]
except ValueError:
ingredient, note = self.parse_ingredient(tokens[1:])
food, note = self.parse_food(tokens[1:])
else:
ingredient, note = self.parse_ingredient(tokens[1:])
food, note = self.parse_food(tokens[1:])
else:
# only two arguments, first one is the amount
# which means this is the ingredient
ingredient = tokens[1]
# which means this is the food
food = tokens[1]
except ValueError:
try:
# can't parse first argument as amount
# -> no unit -> parse everything as ingredient
ingredient, note = self.parse_ingredient(tokens)
# -> no unit -> parse everything as food
food, note = self.parse_food(tokens)
except ValueError:
ingredient = ' '.join(tokens[1:])
food = ' '.join(tokens[1:])
if unit_note not in note:
note += ' ' + unit_note
return amount, self.apply_unit_automation(unit.strip()), self.apply_food_automation(ingredient.strip()), note.strip()
if unit:
unit = self.apply_unit_automation(unit.strip())
food = self.apply_food_automation(food.strip())
if len(food) > Food._meta.get_field('name').max_length: # test if food name is to long
# try splitting it at a space and taking only the first arg
if len(food.split()) > 1 and len(food.split()[0]) < Food._meta.get_field('name').max_length:
note = ' '.join(food.split()[1:]) + ' ' + note
food = food.split()[0]
else:
note = food + ' ' + note
food = food[:Food._meta.get_field('name').max_length]
if len(food.strip()) == 0:
raise ValueError(f'Error parsing string {ingredient}, food cannot be empty')
return amount, unit, food, note[:Ingredient._meta.get_field('note').max_length].strip()

View File

@@ -1,18 +1,15 @@
"""
Source: https://djangosnippets.org/snippets/1703/
"""
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test
from django.core.cache import caches
from django.core.exceptions import ValidationError
from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.http import HttpResponseRedirect
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext as _
from rest_framework import permissions
from rest_framework.permissions import SAFE_METHODS
from cookbook.models import ShareLink
from cookbook.models import ShareLink, Recipe, UserPreference, UserSpace
def get_allowed_groups(groups_required):
@@ -43,8 +40,11 @@ def has_group_permission(user, groups):
return False
groups_allowed = get_allowed_groups(groups)
if user.is_authenticated:
if bool(user.groups.filter(name__in=groups_allowed)):
return True
if user_space := user.userspace_set.filter(active=True):
if len(user_space) != 1:
return False # do not allow any group permission if more than one space is active, needs to be changed when simultaneous multi-space-tenancy is added
if bool(user_space.first().groups.filter(name__in=groups_allowed)):
return True
return False
@@ -53,7 +53,6 @@ def is_object_owner(user, obj):
Tests if a given user is the owner of a given object
test performed by checking user against the objects user
and create_by field (if exists)
superusers bypass all checks, unauthenticated users cannot own anything
:param user django auth user object
:param obj any object that should be tested
:return: true if user is owner of object, false otherwise
@@ -66,11 +65,25 @@ def is_object_owner(user, obj):
return False
def is_space_owner(user, obj):
"""
Tests if a given user is the owner the space of a given object
:param user django auth user object
:param obj any object that should be tested
:return: true if user is owner of the objects space, false otherwise
"""
if not user.is_authenticated:
return False
try:
return obj.get_space().get_owner() == user
except Exception:
return False
def is_object_shared(user, obj):
"""
Tests if a given user is shared for a given object
test performed by checking user against the objects shared table
superusers bypass all checks, unauthenticated users cannot own anything
:param user django auth user object
:param obj any object that should be tested
:return: true if user is shared for object, false otherwise
@@ -166,7 +179,7 @@ class OwnerRequiredMixin(object):
try:
obj = self.get_object()
if obj.get_space() != request.space:
if not request.user.userspace.filter(space=obj.get_space()).exists():
messages.add_message(request, messages.ERROR,
_('You do not have the required permissions to view this page!'))
return HttpResponseRedirect(reverse_lazy('index'))
@@ -184,7 +197,7 @@ class CustomIsOwner(permissions.BasePermission):
verifies user has ownership over object
(either user or created_by or user is request user)
"""
message = _('You cannot interact with this object as it is not owned by you!') # noqa: E501
message = _('You cannot interact with this object as it is not owned by you!')
def has_permission(self, request, view):
return request.user.is_authenticated
@@ -193,6 +206,28 @@ class CustomIsOwner(permissions.BasePermission):
return is_object_owner(request.user, obj)
class CustomIsOwnerReadOnly(CustomIsOwner):
def has_permission(self, request, view):
return super().has_permission(request, view) and request.method in SAFE_METHODS
def has_object_permission(self, request, view, obj):
return super().has_object_permission(request, view) and request.method in SAFE_METHODS
class CustomIsSpaceOwner(permissions.BasePermission):
"""
Custom permission class for django rest framework views
verifies if the user is the owner of the space the object belongs to
"""
message = _('You cannot interact with this object as it is not owned by you!')
def has_permission(self, request, view):
return request.user.is_authenticated and request.space.created_by == request.user
def has_object_permission(self, request, view, obj):
return is_space_owner(request.user, obj)
# TODO function duplicate/too similar name
class CustomIsShared(permissions.BasePermission):
"""
@@ -262,3 +297,58 @@ class CustomIsShare(permissions.BasePermission):
if share:
return share_link_valid(obj, share)
return False
def above_space_limit(space): # TODO add file storage limit
"""
Test if the space has reached any limit (e.g. max recipes, users, ..)
:param space: Space to test for limits
:return: Tuple (True if above or equal any limit else false, message)
"""
r_limit, r_msg = above_space_recipe_limit(space)
u_limit, u_msg = above_space_user_limit(space)
return r_limit or u_limit, (r_msg + ' ' + u_msg).strip()
def above_space_recipe_limit(space):
"""
Test if a space has reached its recipe limit
:param space: Space to test for limits
:return: Tuple (True if above or equal limit else false, message)
"""
limit = space.max_recipes != 0 and Recipe.objects.filter(space=space).count() >= space.max_recipes
if limit:
return True, _('You have reached the maximum number of recipes for your space.')
return False, ''
def above_space_user_limit(space):
"""
Test if a space has reached its user limit
:param space: Space to test for limits
:return: Tuple (True if above or equal limit else false, message)
"""
limit = space.max_users != 0 and UserSpace.objects.filter(space=space).count() > space.max_users
if limit:
return True, _('You have more users than allowed in your space.')
return False, ''
def switch_user_active_space(user, space):
"""
Switch the currently active space of a user by setting all spaces to inactive and activating the one passed
:param user: user to change active space for
:param space: space to activate user for
:return user space object or none if not found/no permission
"""
try:
us = UserSpace.objects.get(space=space, user=user)
if not us.active:
UserSpace.objects.filter(user=user).update(active=False)
us.active = True
us.save()
return us
else:
return us
except ObjectDoesNotExist:
return None

View File

@@ -1,194 +1,191 @@
import json
import re
from json import JSONDecodeError
from urllib.parse import unquote
# import json
# import re
# from json import JSONDecodeError
# from urllib.parse import unquote
from bs4 import BeautifulSoup
from bs4.element import Tag
from recipe_scrapers._utils import get_host_name, normalize_string
# from bs4 import BeautifulSoup
# from bs4.element import Tag
# from recipe_scrapers import scrape_html, scrape_me
# from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
# from recipe_scrapers._utils import get_host_name, normalize_string
from cookbook.helper import recipe_url_import as helper
from cookbook.helper.scrapers.scrapers import text_scraper
# from cookbook.helper import recipe_url_import as helper
# from cookbook.helper.scrapers.scrapers import text_scraper
def get_recipe_from_source(text, url, request):
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 + ": " + normalize_string(str(v)),
'value': normalize_string(str(v))
}
return node
# def get_recipe_from_source(text, url, request):
# 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 + ": " + normalize_string(str(v)),
# 'value': normalize_string(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_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': normalize_string(str(kid)),
'value': normalize_string(str(kid))
})
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': normalize_string(str(kid)),
# 'value': normalize_string(str(kid))
# })
# return kid_list
recipe_json = {
'name': '',
'url': '',
'description': '',
'image': '',
'keywords': [],
'recipeIngredient': [],
'recipeInstructions': '',
'servings': '',
'prepTime': '',
'cookTime': ''
}
recipe_tree = []
parse_list = []
html_data = []
images = []
text = unquote(text)
# recipe_tree = []
# parse_list = []
# soup = BeautifulSoup(text, "html.parser")
# html_data = get_from_html(soup)
# images = get_images_from_source(soup, url)
# text = unquote(text)
# scrape = None
try:
parse_list.append(remove_graph(json.loads(text)))
if not url and 'url' in parse_list[0]:
url = parse_list[0]['url']
scrape = text_scraper("<script type='application/ld+json'>" + text + "</script>", url=url)
# if url and not text:
# try:
# scrape = scrape_me(url_path=url, wild_mode=True)
# except(NoSchemaFoundInWildMode):
# pass
except JSONDecodeError:
soup = BeautifulSoup(text, "html.parser")
html_data = get_from_html(soup)
images += get_images_from_source(soup, url)
for el in soup.find_all('script', type='application/ld+json'):
el = remove_graph(el)
if not url and 'url' in el:
url = el['url']
if type(el) == list:
for le in el:
parse_list.append(le)
elif type(el) == dict:
parse_list.append(el)
for el in soup.find_all(type='application/json'):
el = remove_graph(el)
if type(el) == list:
for le in el:
parse_list.append(le)
elif type(el) == dict:
parse_list.append(el)
scrape = text_scraper(text, url=url)
# if not scrape:
# try:
# parse_list.append(remove_graph(json.loads(text)))
# if not url and 'url' in parse_list[0]:
# url = parse_list[0]['url']
# scrape = text_scraper("<script type='application/ld+json'>" + text + "</script>", url=url)
recipe_json = helper.get_from_scraper(scrape, request)
# except JSONDecodeError:
# for el in soup.find_all('script', type='application/ld+json'):
# el = remove_graph(el)
# if not url and 'url' in el:
# url = el['url']
# if type(el) == list:
# for le in el:
# parse_list.append(le)
# elif type(el) == dict:
# parse_list.append(el)
# for el in soup.find_all(type='application/json'):
# el = remove_graph(el)
# if type(el) == list:
# for le in el:
# parse_list.append(le)
# elif type(el) == dict:
# parse_list.append(el)
# scrape = text_scraper(text, url=url)
for el in parse_list:
temp_tree = []
if isinstance(el, Tag):
try:
el = json.loads(el.string)
except TypeError:
continue
# recipe_json = helper.get_from_scraper(scrape, request)
for k, v in el.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 + ": " + normalize_string(str(v)),
'value': normalize_string(str(v))
}
temp_tree.append(node)
# # TODO: DEPRECATE recipe_tree & html_data. first validate it isn't used anywhere
# for el in parse_list:
# temp_tree = []
# if isinstance(el, Tag):
# try:
# el = json.loads(el.string)
# except TypeError:
# continue
if '@type' in el and el['@type'] == 'Recipe':
recipe_tree += [{'name': 'ld+json', 'children': temp_tree}]
else:
recipe_tree += [{'name': 'json', 'children': temp_tree}]
# for k, v in el.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 + ": " + normalize_string(str(v)),
# 'value': normalize_string(str(v))
# }
# temp_tree.append(node)
return recipe_json, recipe_tree, html_data, images
# if '@type' in el and el['@type'] == 'Recipe':
# recipe_tree += [{'name': 'ld+json', 'children': temp_tree}]
# else:
# recipe_tree += [{'name': 'json', 'children': temp_tree}]
# return recipe_json, recipe_tree, html_data, images
def get_from_html(soup):
INVISIBLE_ELEMS = ('style', 'script', 'head', 'title')
html = []
for s in soup.strings:
if ((s.parent.name not in INVISIBLE_ELEMS) and (len(s.strip()) > 0)):
html.append(s)
return html
# def get_from_html(soup):
# INVISIBLE_ELEMS = ('style', 'script', 'head', 'title')
# html = []
# for s in soup.strings:
# if ((s.parent.name not in INVISIBLE_ELEMS) and (len(s.strip()) > 0)):
# html.append(s)
# return html
def get_images_from_source(soup, url):
sources = ['src', 'srcset', 'data-src']
images = []
img_tags = soup.find_all('img')
if url:
site = get_host_name(url)
prot = url.split(':')[0]
# def get_images_from_source(soup, url):
# sources = ['src', 'srcset', 'data-src']
# images = []
# img_tags = soup.find_all('img')
# if url:
# site = get_host_name(url)
# prot = url.split(':')[0]
urls = []
for img in img_tags:
for src in sources:
try:
urls.append(img[src])
except KeyError:
pass
# urls = []
# for img in img_tags:
# for src in sources:
# try:
# urls.append(img[src])
# except KeyError:
# pass
for u in urls:
u = u.split('?')[0]
filename = re.search(r'/([\w_-]+[.](jpg|jpeg|gif|png))$', u)
if filename:
if (('http' not in u) and (url)):
# sometimes an image source can be relative
# if it is provide the base url
u = '{}://{}{}'.format(prot, site, u)
if 'http' in u:
images.append(u)
return images
# for u in urls:
# u = u.split('?')[0]
# filename = re.search(r'/([\w_-]+[.](jpg|jpeg|gif|png))$', u)
# if filename:
# if (('http' not in u) and (url)):
# # sometimes an image source can be relative
# # if it is provide the base url
# u = '{}://{}{}'.format(prot, site, u)
# if 'http' in u:
# images.append(u)
# return images
def remove_graph(el):
# recipes type might be wrapped in @graph type
if isinstance(el, Tag):
try:
el = json.loads(el.string)
if '@graph' in el:
for x in el['@graph']:
if '@type' in x and x['@type'] == 'Recipe':
el = x
except (TypeError, JSONDecodeError):
pass
return el
# def remove_graph(el):
# # recipes type might be wrapped in @graph type
# if isinstance(el, Tag):
# try:
# el = json.loads(el.string)
# if '@graph' in el:
# for x in el['@graph']:
# if '@type' in x and x['@type'] == 'Recipe':
# el = x
# except (TypeError, JSONDecodeError):
# pass
# return el

View File

@@ -4,7 +4,8 @@ from datetime import date, timedelta
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector, TrigramSimilarity
from django.core.cache import caches
from django.db.models import Avg, Case, Count, F, Func, Max, OuterRef, Q, Subquery, Sum, Value, When
from django.db.models import (Avg, Case, Count, Exists, F, Func, Max, OuterRef, Q, Subquery, Sum,
Value, When)
from django.db.models.functions import Coalesce, Lower, Substr
from django.utils import timezone, translation
from django.utils.translation import gettext as _
@@ -147,7 +148,7 @@ class RecipeSearch():
def _build_sort_order(self):
if self._random:
self._queryset = self._queryset.order_by("?")
self.orderby = ['?']
else:
order = []
# TODO add userpreference for default sort order and replace '-favorite'
@@ -525,16 +526,18 @@ class RecipeSearch():
@ staticmethod
def __children_substitute_filter(shopping_users=None):
children_onhand_subquery = Food.objects.filter(
path__startswith=Substr(OuterRef('path'), 1, Food.steplen*OuterRef('depth')),
path__startswith=OuterRef('path'),
depth__gt=OuterRef('depth'),
onhand_users__in=shopping_users
).annotate(child_onhand=Coalesce(Func('pk', function='Count'), 0)).values('child_onhand')
)
return Food.objects.exclude( # list of foods that are onhand and children of: foods that are not onhand and are set to use children as substitutes
Q(onhand_users__in=shopping_users)
| Q(ignore_shopping=True, recipe__isnull=True)
| Q(substitute__onhand_users__in=shopping_users)
).exclude(depth=1, numchild=0).filter(substitute_children=True
).annotate(child_onhand=Coalesce(Subquery(children_onhand_subquery), 0)).exclude(child_onhand=0)
).exclude(depth=1, numchild=0
).filter(substitute_children=True
).annotate(child_onhand_count=Exists(children_onhand_subquery)
).filter(child_onhand_count=True)
@ staticmethod
def __sibling_substitute_filter(shopping_users=None):
@@ -542,13 +545,15 @@ class RecipeSearch():
path__startswith=Substr(OuterRef('path'), 1, Food.steplen*(OuterRef('depth')-1)),
depth=OuterRef('depth'),
onhand_users__in=shopping_users
).annotate(sibling_onhand=Coalesce(Func('pk', function='Count'), 0)).values('sibling_onhand')
)
return Food.objects.exclude( # list of foods that are onhand and siblings of: foods that are not onhand and are set to use siblings as substitutes
Q(onhand_users__in=shopping_users)
| Q(ignore_shopping=True, recipe__isnull=True)
| Q(substitute__onhand_users__in=shopping_users)
).exclude(depth=1, numchild=0).filter(substitute_siblings=True
).annotate(sibling_onhand=Coalesce(Subquery(sibling_onhand_subquery), 0)).exclude(sibling_onhand=0)
).exclude(depth=1, numchild=0
).filter(substitute_siblings=True
).annotate(sibling_onhand=Exists(sibling_onhand_subquery)
).filter(sibling_onhand=True)
class RecipeFacet():
@@ -760,6 +765,6 @@ def old_search(request):
params = dict(request.GET)
params['internal'] = None
f = RecipeFilter(params,
queryset=Recipe.objects.filter(space=request.user.userpreference.space).all().order_by(Lower('name').asc()),
queryset=Recipe.objects.filter(space=request.space).all().order_by(Lower('name').asc()),
space=request.space)
return f.qs

View File

@@ -7,12 +7,15 @@ from django.utils.dateparse import parse_duration
from django.utils.translation import gettext as _
from isodate import parse_duration as iso_parse_duration
from isodate.isoerror import ISO8601Error
from recipe_scrapers._utils import get_minutes
from pytube import YouTube
from recipe_scrapers._utils import get_host_name, get_minutes
from cookbook.helper import recipe_url_import as helper
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.models import Keyword
# from recipe_scrapers._utils import get_minutes ## temporary until/unless upstream incorporates get_minutes() PR
def get_from_scraper(scrape, request):
# converting the scrape_me object to the existing json format based on ld+json
@@ -28,7 +31,7 @@ def get_from_scraper(scrape, request):
recipe_json['name'] = ''
try:
description = scrape.description() or None
description = scrape.description() or None
except Exception:
description = None
if not description:
@@ -37,45 +40,37 @@ def get_from_scraper(scrape, request):
except Exception:
description = ''
recipe_json['description'] = parse_description(description)
recipe_json['internal'] = True
try:
servings = scrape.yields() or None
servings = scrape.schema.data.get('recipeYield') or 1 # dont use scrape.yields() as this will always return "x servings" or "x items", should be improved in scrapers directly
except Exception:
servings = None
if not servings:
try:
servings = scrape.schema.data.get('recipeYield') or 1
except Exception:
servings = 1
if type(servings) != int:
try:
servings = int(re.findall(r'\b\d+\b', servings)[0])
except Exception:
servings = 1
recipe_json['servings'] = max(servings, 1)
servings = 1
recipe_json['servings'] = parse_servings(servings)
recipe_json['servings_text'] = parse_servings_text(servings)
try:
recipe_json['prepTime'] = get_minutes(scrape.prep_time()) or 0
recipe_json['working_time'] = get_minutes(scrape.prep_time()) or 0
except Exception:
try:
recipe_json['prepTime'] = get_minutes(scrape.schema.data.get("prepTime")) or 0
recipe_json['working_time'] = get_minutes(scrape.schema.data.get("prepTime")) or 0
except Exception:
recipe_json['prepTime'] = 0
recipe_json['working_time'] = 0
try:
recipe_json['cookTime'] = get_minutes(scrape.cook_time()) or 0
recipe_json['waiting_time'] = get_minutes(scrape.cook_time()) or 0
except Exception:
try:
recipe_json['cookTime'] = get_minutes(scrape.schema.data.get("cookTime")) or 0
recipe_json['waiting_time'] = get_minutes(scrape.schema.data.get("cookTime")) or 0
except Exception:
recipe_json['cookTime'] = 0
recipe_json['waiting_time'] = 0
if recipe_json['cookTime'] + recipe_json['prepTime'] == 0:
if recipe_json['working_time'] + recipe_json['waiting_time'] == 0:
try:
recipe_json['prepTime'] = get_minutes(scrape.total_time()) or 0
recipe_json['working_time'] = get_minutes(scrape.total_time()) or 0
except Exception:
try:
recipe_json['prepTime'] = get_minutes(scrape.schema.data.get("totalTime")) or 0
recipe_json['working_time'] = get_minutes(scrape.schema.data.get("totalTime")) or 0
except Exception:
pass
@@ -113,6 +108,21 @@ def get_from_scraper(scrape, request):
keywords += listify_keywords(scrape.schema.data.get("recipeCuisine"))
except Exception:
pass
try:
source_url = scrape.canonical_url()
except Exception:
try:
source_url = scrape.url
except Exception:
pass
if source_url:
recipe_json['source_url'] = source_url
try:
keywords.append(source_url.replace('http://', '').replace('https://', '').split('/')[0])
except Exception:
pass
try:
recipe_json['keywords'] = parse_keywords(list(set(map(str.casefold, keywords))), request.space)
except AttributeError:
@@ -120,55 +130,84 @@ def get_from_scraper(scrape, request):
ingredient_parser = IngredientParser(request, True)
ingredients = []
recipe_json['steps'] = []
try:
for i in parse_instructions(scrape.instructions()):
recipe_json['steps'].append({'instruction': i, 'ingredients': [], })
except Exception:
pass
if len(recipe_json['steps']) == 0:
recipe_json['steps'].append({'instruction': '', 'ingredients': [], })
if len(parse_description(description)) > 256: # split at 256 as long descriptions dont look good on recipe cards
recipe_json['steps'][0]['instruction'] = f'*{parse_description(description)}* \n\n' + recipe_json['steps'][0]['instruction']
else:
recipe_json['description'] = parse_description(description)[:512]
try:
for x in scrape.ingredients():
try:
amount, unit, ingredient, note = ingredient_parser.parse(x)
ingredients.append(
{
'amount': amount,
'unit': {
'text': unit,
'id': random.randrange(10000, 99999)
},
'ingredient': {
'text': ingredient,
'id': random.randrange(10000, 99999)
},
'note': note,
'original_text': x
}
)
ingredient = {
'amount': amount,
'food': {
'name': ingredient,
},
'unit': None,
'note': note,
'original_text': x
}
if unit:
ingredient['unit'] = {'name': unit, }
recipe_json['steps'][0]['ingredients'].append(ingredient)
except Exception:
ingredients.append(
recipe_json['steps'][0]['ingredients'].append(
{
'amount': 0,
'unit': {
'text': '',
'id': random.randrange(10000, 99999)
},
'ingredient': {
'text': x,
'id': random.randrange(10000, 99999)
'unit': None,
'food': {
'name': x,
},
'note': '',
'original_text': x
}
)
recipe_json['recipeIngredient'] = ingredients
except Exception:
recipe_json['recipeIngredient'] = ingredients
pass
return recipe_json
def get_from_youtube_scraper(url, request):
"""A YouTube Information Scraper."""
kw, created = Keyword.objects.get_or_create(name='YouTube', space=request.space)
default_recipe_json = {
'name': '',
'internal': True,
'description': '',
'servings': 1,
'working_time': 0,
'waiting_time': 0,
'image': "",
'keywords': [{'name': kw.name, 'label': kw.name, 'id': kw.pk}],
'source_url': url,
'steps': [
{
'ingredients': [],
'instruction': ''
}
]
}
try:
recipe_json['recipeInstructions'] = parse_instructions(scrape.instructions())
video = YouTube(url=url)
default_recipe_json['name'] = video.title
default_recipe_json['image'] = video.thumbnail_url
default_recipe_json['steps'][0]['instruction'] = video.description
except Exception:
recipe_json['recipeInstructions'] = ""
pass
if scrape.canonical_url():
recipe_json['url'] = scrape.canonical_url()
recipe_json['recipeInstructions'] += "\n\n" + _("Imported from") + ": " + scrape.canonical_url()
return recipe_json
return default_recipe_json
def parse_name(name):
@@ -180,102 +219,46 @@ def parse_name(name):
return normalize_string(name)
def parse_ingredients(ingredients):
# some pages have comma separated ingredients in a single array entry
try:
if type(ingredients[0]) == dict:
return ingredients
except (KeyError, IndexError):
pass
if (len(ingredients) == 1 and type(ingredients) == list):
ingredients = ingredients[0].split(',')
elif type(ingredients) == str:
ingredients = ingredients.split(',')
for x in ingredients:
if '\n' in x:
ingredients.remove(x)
for i in x.split('\n'):
ingredients.insert(0, i)
ingredient_list = []
for x in ingredients:
if x.replace(' ', '') != '':
x = x.replace('&frac12;', "0.5").replace('&frac14;', "0.25").replace('&frac34;', "0.75")
try:
amount, unit, ingredient, note = parse_single_ingredient(x)
if ingredient:
ingredient_list.append(
{
'amount': amount,
'unit': {
'text': unit,
'id': random.randrange(10000, 99999)
},
'ingredient': {
'text': ingredient,
'id': random.randrange(10000, 99999)
},
'note': note,
'original_text': x
}
)
except Exception:
ingredient_list.append(
{
'amount': 0,
'unit': {
'text': '',
'id': random.randrange(10000, 99999)
},
'ingredient': {
'text': x,
'id': random.randrange(10000, 99999)
},
'note': '',
'original_text': x
}
)
ingredients = ingredient_list
else:
ingredients = []
return ingredients
def parse_description(description):
return normalize_string(description)
def parse_instructions(instructions):
instruction_text = ''
# flatten instructions if they are in a list
if type(instructions) == list:
for i in instructions:
if type(i) == str:
instruction_text += i
else:
if 'text' in i:
instruction_text += i['text'] + '\n\n'
elif 'itemListElement' in i:
for ile in i['itemListElement']:
if type(ile) == str:
instruction_text += ile + '\n\n'
elif 'text' in ile:
instruction_text += ile['text'] + '\n\n'
else:
instruction_text += str(i)
instructions = instruction_text
normalized_string = normalize_string(instructions)
def clean_instruction_string(instruction):
normalized_string = normalize_string(instruction)
normalized_string = normalized_string.replace('\n', ' \n')
normalized_string = normalized_string.replace(' \n \n', '\n\n')
return normalized_string
def parse_instructions(instructions):
"""
Convert arbitrary instructions object from website import and turn it into a flat list of strings
:param instructions: any instructions object from import
:return: list of strings (from one to many elements depending on website)
"""
instruction_list = []
if type(instructions) == list:
for i in instructions:
if type(i) == str:
instruction_list.append(clean_instruction_string(i))
else:
if 'text' in i:
instruction_list.append(clean_instruction_string(i['text']))
elif 'itemListElement' in i:
for ile in i['itemListElement']:
if type(ile) == str:
instruction_list.append(clean_instruction_string(ile))
elif 'text' in ile:
instruction_list.append(clean_instruction_string(ile['text']))
else:
instruction_list.append(clean_instruction_string(str(i)))
else:
instruction_list.append(clean_instruction_string(instructions))
return instruction_list
def parse_image(image):
# check if list of images is returned, take first if so
if not image:
@@ -310,40 +293,31 @@ def parse_servings(servings):
return servings
def parse_cooktime(cooktime):
if type(cooktime) not in [int, float]:
def parse_servings_text(servings):
if type(servings) == str:
try:
cooktime = float(re.search(r'\d+', cooktime).group())
servings = re.sub("\d+", '', servings).strip()
except Exception:
servings = ''
return str(servings)[:32]
def parse_time(recipe_time):
if type(recipe_time) not in [int, float]:
try:
recipe_time = float(re.search(r'\d+', recipe_time).group())
except (ValueError, AttributeError):
try:
cooktime = round(iso_parse_duration(cooktime).seconds / 60)
recipe_time = round(iso_parse_duration(recipe_time).seconds / 60)
except ISO8601Error:
try:
if (type(cooktime) == list and len(cooktime) > 0):
cooktime = cooktime[0]
cooktime = round(parse_duration(cooktime).seconds / 60)
if (type(recipe_time) == list and len(recipe_time) > 0):
recipe_time = recipe_time[0]
recipe_time = round(parse_duration(recipe_time).seconds / 60)
except AttributeError:
cooktime = 0
recipe_time = 0
return cooktime
def parse_preptime(preptime):
if type(preptime) not in [int, float]:
try:
preptime = float(re.search(r'\d+', preptime).group())
except ValueError:
try:
preptime = round(iso_parse_duration(preptime).seconds / 60)
except ISO8601Error:
try:
if (type(preptime) == list and len(preptime) > 0):
preptime = preptime[0]
preptime = round(parse_duration(preptime).seconds / 60)
except AttributeError:
preptime = 0
return preptime
return recipe_time
def parse_keywords(keyword_json, space):
@@ -353,9 +327,9 @@ def parse_keywords(keyword_json, space):
kw = normalize_string(kw)
if len(kw) != 0:
if k := Keyword.objects.filter(name=kw, space=space).first():
keywords.append({'id': str(k.id), 'text': str(k.name)})
keywords.append({'label': str(k), 'name': k.name, 'id': k.id})
else:
keywords.append({'id': random.randrange(1111111, 9999999, 1), 'text': kw})
keywords.append({'label': kw, 'name': kw})
return keywords
@@ -393,3 +367,32 @@ def iso_duration_to_minutes(string):
string
).groupdict()
return int(match['days'] or 0) * 24 * 60 + int(match['hours'] or 0) * 60 + int(match['minutes'] or 0)
def get_images_from_soup(soup, url):
sources = ['src', 'srcset', 'data-src']
images = []
img_tags = soup.find_all('img')
if url:
site = get_host_name(url)
prot = url.split(':')[0]
urls = []
for img in img_tags:
for src in sources:
try:
urls.append(img[src])
except KeyError:
pass
for u in urls:
u = u.split('?')[0]
filename = re.search(r'/([\w_-]+[.](jpg|jpeg|gif|png))$', u)
if filename:
if (('http' not in u) and (url)):
# sometimes an image source can be relative
# if it is provide the base url
u = '{}://{}{}'.format(prot, site, u)
if 'http' in u:
images.append(u)
return images

View File

@@ -14,6 +14,12 @@ class ScopeMiddleware:
def __call__(self, request):
prefix = settings.JS_REVERSE_SCRIPT_PREFIX or ''
# need to disable scopes for writing requests into userpref and enable for loading ?
if request.path.startswith(prefix + '/api/user-preference/'):
with scopes_disabled():
return self.get_response(request)
if request.user.is_authenticated:
if request.path.startswith(prefix + '/admin/'):
@@ -26,14 +32,23 @@ class ScopeMiddleware:
if request.path.startswith(prefix + '/accounts/'):
return self.get_response(request)
with scopes_disabled():
if request.user.userpreference.space is None and not reverse('account_logout') in request.path:
return views.no_space(request)
if request.path.startswith(prefix + '/switch-space/'):
return self.get_response(request)
if request.user.groups.count() == 0 and not reverse('account_logout') in request.path:
with scopes_disabled():
if request.user.userspace_set.count() == 0 and not reverse('account_logout') in request.path:
return views.space_overview(request)
# get active user space, if for some reason more than one space is active select first (group permission checks will fail, this is not intended at this point)
user_space = request.user.userspace_set.filter(active=True).first()
if not user_space:
return views.space_overview(request)
if user_space.groups.count() == 0 and not reverse('account_logout') in request.path:
return views.no_groups(request)
request.space = request.user.userpreference.space
request.space = user_space.space
# with scopes_disabled():
with scope(space=request.space):
return self.get_response(request)
@@ -41,9 +56,11 @@ class ScopeMiddleware:
if request.path.startswith(prefix + '/api/'):
try:
if auth := TokenAuthentication().authenticate(request):
request.space = auth[0].userpreference.space
with scope(space=request.space):
return self.get_response(request)
user_space = auth[0].userspace_set.filter(active=True).first()
if user_space:
request.space = user_space.space
with scope(space=request.space):
return self.get_response(request)
except AuthenticationFailed:
pass

View File

@@ -1,5 +1,6 @@
from bs4 import BeautifulSoup
from json import JSONDecodeError
from bs4 import BeautifulSoup
from recipe_scrapers import SCRAPERS, get_host_name
from recipe_scrapers._factory import SchemaScraperFactory
from recipe_scrapers._schemaorg import SchemaOrg
@@ -26,17 +27,17 @@ def text_scraper(text, url=None):
class TextScraper(scraper_class):
def __init__(
self,
page_data,
url=None
html=None,
url=None,
):
self.wild_mode = False
self.meta_http_equiv = False
self.soup = BeautifulSoup(page_data, "html.parser")
self.soup = BeautifulSoup(html, "html.parser")
self.url = url
self.recipe = None
try:
self.schema = SchemaOrg(page_data)
self.schema = SchemaOrg(html)
except (JSONDecodeError, AttributeError):
pass
return TextScraper(text, url)
return TextScraper(url=url, html=text)

View File

@@ -6,11 +6,13 @@ from gettext import gettext as _
from io import BytesIO
import requests
import validators
import yaml
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_html_import import get_recipe_from_source
from cookbook.helper.recipe_url_import import iso_duration_to_minutes
from cookbook.helper.recipe_url_import import (get_from_scraper, get_images_from_soup,
iso_duration_to_minutes)
from cookbook.helper.scrapers.scrapers import text_scraper
from cookbook.integration.integration import Integration
from cookbook.models import Ingredient, Keyword, Recipe, Step
@@ -23,7 +25,10 @@ class CookBookApp(Integration):
def get_recipe_from_file(self, file):
recipe_html = file.getvalue().decode("utf-8")
recipe_json, recipe_tree, html_data, images = get_recipe_from_source(recipe_html, 'CookBookApp', self.request)
# recipe_json, recipe_tree, html_data, images = get_recipe_from_source(recipe_html, 'CookBookApp', self.request)
scrape = text_scraper(text=recipe_html)
recipe_json = get_from_scraper(scrape, self.request)
images = list(dict.fromkeys(get_images_from_soup(scrape.soup, None)))
recipe = Recipe.objects.create(
name=recipe_json['name'].strip(),
@@ -41,7 +46,8 @@ class CookBookApp(Integration):
except Exception:
pass
step = Step.objects.create(instruction=recipe_json['recipeInstructions'], space=self.request.space, )
# assuming import files only contain single step
step = Step.objects.create(instruction=recipe_json['steps'][0]['instruction'], space=self.request.space, )
if 'nutrition' in recipe_json:
step.instruction = step.instruction + '\n\n' + recipe_json['nutrition']
@@ -50,17 +56,21 @@ class CookBookApp(Integration):
recipe.steps.add(step)
ingredient_parser = IngredientParser(self.request, True)
for ingredient in recipe_json['recipeIngredient']:
f = ingredient_parser.get_food(ingredient['ingredient']['text'])
u = ingredient_parser.get_unit(ingredient['unit']['text'])
for ingredient in recipe_json['steps'][0]['ingredients']:
f = ingredient_parser.get_food(ingredient['food']['name'])
u = None
if unit := ingredient.get('unit', None):
u = ingredient_parser.get_unit(unit.get('name', None))
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=ingredient['amount'], note=ingredient['note'], space=self.request.space,
food=f, unit=u, amount=ingredient.get('amount', None), note=ingredient.get('note', None), original_text=ingredient.get('original_text', None), space=self.request.space,
))
if len(images) > 0:
try:
response = requests.get(images[0])
self.import_recipe_image(recipe, BytesIO(response.content))
url = images[0]
if validators.url(url, public=True):
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
except Exception as e:
print('failed to import image ', str(e))

View File

@@ -0,0 +1,88 @@
import base64
import json
from io import BytesIO
from gettext import gettext as _
import requests
import validators
from lxml import etree
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_url_import import parse_servings, parse_time, parse_servings_text
from cookbook.integration.integration import Integration
from cookbook.models import Ingredient, Keyword, Recipe, Step
class Cookmate(Integration):
def import_file_name_filter(self, zip_info_object):
return zip_info_object.filename.endswith('.xml')
def get_files_from_recipes(self, recipes, el, cookie):
raise NotImplementedError('Method not implemented in storage integration')
def get_recipe_from_file(self, file):
recipe_xml = file
recipe = Recipe.objects.create(
name=recipe_xml.find('title').text.strip(),
created_by=self.request.user, internal=True, space=self.request.space)
if recipe_xml.find('preptime') is not None and recipe_xml.find('preptime').text is not None:
recipe.working_time = parse_time(recipe_xml.find('preptime').text.strip())
if recipe_xml.find('cooktime') is not None and recipe_xml.find('cooktime').text is not None:
recipe.waiting_time = parse_time(recipe_xml.find('cooktime').text.strip())
if recipe_xml.find('quantity') is not None and recipe_xml.find('quantity').text is not None:
recipe.servings = parse_servings(recipe_xml.find('quantity').text.strip())
recipe.servings_text = parse_servings_text(recipe_xml.find('quantity').text.strip())
if recipe_xml.find('url') is not None and recipe_xml.find('url').text is not None:
recipe.source_url = recipe_xml.find('url').text.strip()
if recipe_xml.find('description') is not None: # description is a list of <li>'s with text
if len(recipe_xml.find('description')) > 0:
recipe.description = recipe_xml.find('description')[0].text[:512]
if recipe_text := recipe_xml.find('recipetext'):
for step in recipe_text.getchildren():
if step.text:
step = Step.objects.create(
instruction=step.text.strip(), space=self.request.space,
)
recipe.steps.add(step)
ingredient_parser = IngredientParser(self.request, True)
if recipe_ingredients := recipe_xml.find('ingredient'):
ingredient_step = recipe.steps.first()
if ingredient_step is None:
ingredient_step = Step.objects.create(space=self.request.space, instruction='')
for ingredient in recipe_ingredients.getchildren():
if ingredient.text:
if ingredient.text.strip() != '':
amount, unit, food, note = ingredient_parser.parse(ingredient.text.strip())
f = ingredient_parser.get_food(food)
u = ingredient_parser.get_unit(unit)
ingredient_step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=amount, note=note, original_text=ingredient.text.strip(), space=self.request.space,
))
if recipe_xml.find('imageurl') is not None:
try:
url = recipe_xml.find('imageurl').text.strip()
if validators.url(url, public=True):
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
except Exception as e:
print('failed to import image ', str(e))
recipe.save()
return recipe
def get_file_from_recipe(self, recipe):
raise NotImplementedError('Method not implemented in storage integration')

View File

@@ -3,10 +3,9 @@ from io import BytesIO
from zipfile import ZipFile
from bs4 import BeautifulSoup
from django.utils.translation import gettext as _
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_html_import import get_recipe_from_source
from cookbook.helper.recipe_url_import import iso_duration_to_minutes, parse_servings
from cookbook.integration.integration import Integration
from cookbook.models import Ingredient, Keyword, Recipe, Step
@@ -32,7 +31,14 @@ class CopyMeThat(Integration):
recipe.servings = parse_servings(file.find("a", {"id": "recipeYield"}).text.strip())
recipe.working_time = iso_duration_to_minutes(file.find("span", {"meta": "prepTime"}).text.strip())
recipe.waiting_time = iso_duration_to_minutes(file.find("span", {"meta": "cookTime"}).text.strip())
recipe.save()
recipe.description = (file.find("div ", {"id": "description"}).text.strip())[:512]
except AttributeError:
pass
try:
if len(file.find("span", {"id": "starred"}).text.strip()) > 0:
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=_('Favorite'))[0])
except AttributeError:
pass

View File

@@ -5,6 +5,8 @@ import traceback
import uuid
from io import BytesIO, StringIO
from zipfile import BadZipFile, ZipFile
import lxml
from django.core.cache import cache
import datetime
@@ -16,6 +18,7 @@ from django.http import HttpResponse
from django.utils.formats import date_format
from django.utils.translation import gettext as _
from django_scopes import scope
from lxml import etree
from cookbook.forms import ImportExportBase
from cookbook.helper.image_processing import get_filetype, handle_image
@@ -144,7 +147,7 @@ class Integration:
il.imported_recipes += 1
il.save()
import_zip.close()
elif '.zip' in f['name'] or '.paprikarecipes' in f['name']:
elif '.zip' in f['name'] or '.paprikarecipes' in f['name'] or '.mcb' in f['name']:
import_zip = ZipFile(f['file'])
file_list = []
for z in import_zip.filelist:
@@ -157,9 +160,16 @@ class Integration:
file_list = self.split_recipe_file(BytesIO(import_zip.read('recipes.html')))
il.total_recipes += len(file_list)
if isinstance(self, cookbook.integration.cookmate.Cookmate):
new_file_list = []
for file in file_list:
new_file_list += etree.parse(BytesIO(import_zip.read(file.filename))).getroot().getchildren()
il.total_recipes = len(new_file_list)
file_list = new_file_list
for z in file_list:
try:
if isinstance(z, Tag):
if not hasattr(z, 'filename') or type(z) == Tag:
recipe = self.get_recipe_from_file(z)
else:
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
@@ -172,7 +182,7 @@ class Integration:
traceback.print_exc()
self.handle_exception(e, log=il, message=f'-------------------- \nERROR \n{e}\n--------------------\n')
import_zip.close()
elif '.json' in f['name'] or '.txt' in f['name'] or '.mmf' in f['name'] or '.rk' in f['name']:
elif '.json' in f['name'] or '.txt' in f['name'] or '.mmf' in f['name'] or '.rk' in f['name'] or '.melarecipe' in f['name']:
data_list = self.split_recipe_file(f['file'])
il.total_recipes += len(data_list)
for d in data_list:
@@ -243,7 +253,7 @@ class Integration:
:param image_file: ByteIO stream containing the image
:param filetype: type of file to write bytes to, default to .jpeg if unknown
"""
recipe.image = File(handle_image(self.request, File(image_file, name='image'), filetype=filetype)[0], name=f'{uuid.uuid4()}_{recipe.pk}{filetype}')
recipe.image = File(handle_image(self.request, File(image_file, name='image'), filetype=filetype), name=f'{uuid.uuid4()}_{recipe.pk}{filetype}')
recipe.save()
def get_recipe_from_file(self, file):

View File

@@ -0,0 +1,83 @@
import base64
import json
from io import BytesIO
from gettext import gettext as _
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_url_import import parse_servings, parse_time
from cookbook.integration.integration import Integration
from cookbook.models import Ingredient, Keyword, Recipe, Step
class MelaRecipes(Integration):
def split_recipe_file(self, file):
return [json.loads(file.getvalue().decode("utf-8"))]
def get_files_from_recipes(self, recipes, el, cookie):
raise NotImplementedError('Method not implemented in storage integration')
def get_recipe_from_file(self, file):
recipe_json = file
recipe = Recipe.objects.create(
name=recipe_json['title'].strip(),
created_by=self.request.user, internal=True, space=self.request.space)
if 'yield' in recipe_json:
recipe.servings = parse_servings(recipe_json['yield'])
if 'cookTime' in recipe_json:
recipe.waiting_time = parse_time(recipe_json['cookTime'])
if 'prepTime' in recipe_json:
recipe.working_time = parse_time(recipe_json['prepTime'])
if 'favorite' in recipe_json and recipe_json['favorite']:
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=_('Favorite'))[0])
if 'categories' in recipe_json:
try:
for x in recipe_json['categories']:
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=x)[0])
except Exception:
pass
instruction = ''
if 'text' in recipe_json:
instruction += f'*{recipe_json["text"].strip()}* \n'
if 'instructions' in recipe_json:
instruction += recipe_json["instructions"].strip() + ' \n'
if 'notes' in recipe_json:
instruction += recipe_json["notes"].strip() + ' \n'
if 'link' in recipe_json:
recipe.source_url = recipe_json['link']
step = Step.objects.create(
instruction=instruction, space=self.request.space,
)
ingredient_parser = IngredientParser(self.request, True)
for ingredient in recipe_json['ingredients'].split('\n'):
if ingredient.strip() != '':
amount, unit, food, note = ingredient_parser.parse(ingredient)
f = ingredient_parser.get_food(food)
u = ingredient_parser.get_unit(unit)
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=amount, note=note, original_text=ingredient, space=self.request.space,
))
recipe.steps.add(step)
if recipe_json.get("images", None):
try:
self.import_recipe_image(recipe, BytesIO(base64.b64decode(recipe_json['images'][0])), filetype='.jpeg')
except Exception:
pass
return recipe
def get_file_from_recipe(self, recipe):
raise NotImplementedError('Method not implemented in storage integration')

View File

@@ -31,6 +31,9 @@ class NextcloudCookbook(Integration):
except Exception:
pass
if 'url' in recipe_json:
recipe.source_url = recipe_json['url'].strip()
if 'recipeCategory' in recipe_json:
try:
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=recipe_json['recipeCategory'])[0])
@@ -40,7 +43,8 @@ class NextcloudCookbook(Integration):
if 'keywords' in recipe_json:
try:
for x in recipe_json['keywords'].split(','):
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=x)[0])
if x.strip() != '':
recipe.keywords.add(Keyword.objects.get_or_create(space=self.request.space, name=x)[0])
except Exception:
pass

View File

@@ -6,6 +6,7 @@ from gettext import gettext as _
from io import BytesIO
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.helper.recipe_url_import import parse_servings, parse_servings_text
from cookbook.integration.integration import Integration
from cookbook.models import Ingredient, Keyword, Recipe, Step
@@ -26,10 +27,9 @@ class Paprika(Integration):
recipe.description = '' if len(recipe_json['description'].strip()) > 500 else recipe_json['description'].strip()
try:
if re.match(r'([0-9])+\s(.)*', recipe_json['servings']):
s = recipe_json['servings'].split(' ')
recipe.servings = s[0]
recipe.servings_text = s[1]
if 'servings' in recipe_json:
recipe.servings = parse_servings(recipe_json['servings'])
recipe.servings_text = parse_servings_text(recipe_json['servings'])
if len(recipe_json['cook_time'].strip()) > 0:
recipe.waiting_time = re.findall(r'\d+', recipe_json['cook_time'])[0]

View File

@@ -49,6 +49,7 @@ class Plantoeat(Integration):
)
if tags:
tags = tags.replace('^',',')
for k in tags.split(','):
keyword, created = Keyword.objects.get_or_create(name=k.strip(), space=self.request.space)
recipe.keywords.add(keyword)
@@ -78,7 +79,11 @@ class Plantoeat(Integration):
current_recipe = ''
for fl in file.readlines():
line = fl.decode("windows-1250")
try:
line = fl.decode("utf-8")
except UnicodeDecodeError:
line = fl.decode("windows-1250")
if line.startswith('--------------'):
if current_recipe != '':
recipe_list.append(current_recipe)

View File

@@ -5,6 +5,7 @@ from io import BytesIO
from zipfile import ZipFile
import requests
import validators
from django.utils.translation import gettext as _
from cookbook.helper.image_processing import get_filetype
@@ -123,11 +124,13 @@ class RecetteTek(Integration):
self.import_recipe_image(recipe, BytesIO(import_zip.read(image_file_name)), filetype=get_filetype(image_file_name))
else:
if file['originalPicture'] != '':
response = requests.get(file['originalPicture'])
if imghdr.what(BytesIO(response.content)) is not None:
self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype(file['originalPicture']))
else:
raise Exception("Original image failed to download.")
url = file['originalPicture']
if validators.url(url, public=True):
response = requests.get(url)
if imghdr.what(BytesIO(response.content)) is not None:
self.import_recipe_image(recipe, BytesIO(response.content), filetype=get_filetype(file['originalPicture']))
else:
raise Exception("Original image failed to download.")
except Exception as e:
print(recipe.name, ': failed to import image ', str(e))

View File

@@ -2,6 +2,7 @@ import json
from io import BytesIO
import requests
import validators
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.integration.integration import Integration
@@ -51,8 +52,10 @@ class RecipeSage(Integration):
if len(file['image']) > 0:
try:
response = requests.get(file['image'][0])
self.import_recipe_image(recipe, BytesIO(response.content))
url = file['image'][0]
if validators.url(url, public=True):
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
except Exception as e:
print('failed to import image ', str(e))
@@ -77,14 +80,13 @@ class RecipeSage(Integration):
}
for s in recipe.steps.all():
if s.type != Step.TIME:
data['recipeInstructions'].append({
'@type': 'HowToStep',
'text': s.instruction
})
data['recipeInstructions'].append({
'@type': 'HowToStep',
'text': s.instruction
})
for i in s.ingredients.all():
data['recipeIngredient'].append(f'{float(i.amount)} {i.unit} {i.food}')
for i in s.ingredients.all():
data['recipeIngredient'].append(f'{float(i.amount)} {i.unit} {i.food}')
return data

View File

@@ -12,33 +12,33 @@ class RezKonv(Integration):
ingredients = []
directions = []
for line in file.replace('\r', '').split('\n'):
for line in file.replace('\r', '').replace('\n\n', '\n').split('\n'):
if 'Titel:' in line:
title = line.replace('Titel:', '').strip()
if 'Kategorien:' in line:
tags = line.replace('Kategorien:', '').strip()
if ingredient_mode and ('quelle' in line.lower() or 'source' in line.lower()):
if ingredient_mode and (
'quelle' in line.lower() or 'source' in line.lower() or (line == '' and len(ingredients) > 0)):
ingredient_mode = False
direction_mode = True
if ingredient_mode:
if line != '' and '===' not in line and 'Zubereitung' not in line:
ingredients.append(line.strip())
if direction_mode:
if line.strip() != '' and line.strip() != '=====':
directions.append(line.strip())
if 'Zutaten:' in line:
if 'Zutaten:' in line or 'Ingredients' in line or 'Menge:' in line:
ingredient_mode = True
if 'Zubereitung:' in line:
ingredient_mode = False
direction_mode = True
recipe = Recipe.objects.create(name=title, created_by=self.request.user, internal=True, space=self.request.space)
recipe = Recipe.objects.create(name=title, created_by=self.request.user, internal=True,
space=self.request.space)
for k in tags.split(','):
keyword, created = Keyword.objects.get_or_create(name=k.strip(), space=self.request.space)
recipe.keywords.add(keyword)
step = Step.objects.create(
instruction='\n'.join(directions) + '\n\n', space=self.request.space,
instruction=' \n'.join(directions) + '\n\n', space=self.request.space,
)
ingredient_parser = IngredientParser(self.request, True)
@@ -60,7 +60,8 @@ class RezKonv(Integration):
def split_recipe_file(self, file):
recipe_list = []
current_recipe = ''
encoding_list = ['windows-1250', 'latin-1'] #TODO build algorithm to try trough encodings and fail if none work, use for all importers
encoding_list = ['windows-1250',
'latin-1'] # TODO build algorithm to try trough encodings and fail if none work, use for all importers
encoding = 'windows-1250'
for fl in file.readlines():
try:

View File

@@ -71,11 +71,10 @@ class Saffron(Integration):
recipeInstructions = []
recipeIngredient = []
for s in recipe.steps.all():
if s.type != Step.TIME:
recipeInstructions.append(s.instruction)
recipeInstructions.append(s.instruction)
for i in s.ingredients.all():
recipeIngredient.append(f'{float(i.amount)} {i.unit} {i.food}')
for i in s.ingredients.all():
recipeIngredient.append(f'{float(i.amount)} {i.unit} {i.food}')
data += "Ingredients: \n"
for ingredient in recipeIngredient:

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-04 12:31+0100\n"
"PO-Revision-Date: 2021-11-06 14:06+0000\n"
"Last-Translator: Nicklas Yli-Länttä <admin@timanttikuutio.eu>\n"
"PO-Revision-Date: 2022-03-18 16:31+0000\n"
"Last-Translator: Stefan Werner <werner@iki.fi>\n"
"Language-Team: Finnish <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/fi/>\n"
"Language: fi\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.8\n"
"X-Generator: Weblate 4.10.1\n"
#: .\cookbook\filters.py:23 .\cookbook\templates\base.html:125
#: .\cookbook\templates\forms\ingredients.html:34
@@ -31,10 +31,12 @@ msgid ""
"Color of the top navigation bar. Not all colors work with all themes, just "
"try them out!"
msgstr ""
"Ylänavigointipalkin väri. Ei kaikki värit toimi kaikkien teemojen kanssa; "
"kokeile!"
#: .\cookbook\forms.py:55
msgid "Default Unit to be used when inserting a new ingredient into a recipe."
msgstr ""
msgstr "Oletusmittayksikkö uuden aineksen lisäämisessä."
#: .\cookbook\forms.py:57
msgid ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-13 22:40+0200\n"
"PO-Revision-Date: 2021-10-23 09:06+0000\n"
"Last-Translator: rustam <uzbekr@gmail.com>\n"
"PO-Revision-Date: 2022-04-07 19:32+0000\n"
"Last-Translator: Artem Aksenov <artemmillerr@gmail.com>\n"
"Language-Team: Russian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/ru/>\n"
"Language: ru\n"
@@ -18,14 +18,14 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.8\n"
"X-Generator: Weblate 4.10.1\n"
#: .\cookbook\filters.py:23 .\cookbook\templates\base.html:125
#: .\cookbook\templates\forms\ingredients.html:34
#: .\cookbook\templates\space.html:43 .\cookbook\templates\stats.html:28
#: .\cookbook\templates\url_import.html:270
msgid "Ingredients"
msgstr "ингредиенты"
msgstr "Ингредиенты"
#: .\cookbook\forms.py:50
msgid ""
@@ -95,14 +95,14 @@ msgstr ""
#: .\cookbook\forms.py:103 .\cookbook\forms.py:334
#: .\cookbook\templates\url_import.html:154
msgid "Name"
msgstr "Имя"
msgstr "Название"
#: .\cookbook\forms.py:104 .\cookbook\forms.py:335
#: .\cookbook\templates\space.html:39 .\cookbook\templates\stats.html:24
#: .\cookbook\templates\url_import.html:188
#: .\cookbook\templates\url_import.html:573 .\cookbook\views\lists.py:112
msgid "Keywords"
msgstr "Ключевые поля"
msgstr "Ключевые слова"
#: .\cookbook\forms.py:105
msgid "Preparation time in minutes"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
from django.core.management.commands.dumpdata import Command as DumpdataCommand
from django_scopes import scopes_disabled
class Command(DumpdataCommand):
def handle(self, *args, **options):
with scopes_disabled():
return super().handle(*args, **options)

View File

@@ -0,0 +1,8 @@
from django.core.management.commands.loaddata import Command as LoaddataCommand
from django_scopes import scopes_disabled
class Command(LoaddataCommand):
def handle(self, *args, **options):
with scopes_disabled():
return super().handle(*args, **options)

View File

@@ -16,6 +16,7 @@ DICTIONARY = {
'it': 'italian',
# 'lv': 'Latvian',
'es': 'spanish',
'sv': 'swedish',
}

View File

@@ -4,11 +4,12 @@ from django.db import migrations
def create_default_space(apps, schema_editor):
Space = apps.get_model('cookbook', 'Space')
Space.objects.create(
name='Default',
message=''
)
# Space = apps.get_model('cookbook', 'Space')
# Space.objects.create(
# name='Default',
# message=''
# )
pass # Beginning with the multi space tenancy version (~something around 1.3) a default space is no longer needed as the first user can create it after setup
class Migration(migrations.Migration):

View File

@@ -9,8 +9,15 @@ from django.utils import translation
from django_scopes import scopes_disabled
from cookbook.managers import DICTIONARY
from cookbook.models import (Index, PermissionModelMixin, Recipe, Step, allSearchFields,
nameSearchField)
from cookbook.models import (Index, PermissionModelMixin, Recipe, Step, SearchFields)
def allSearchFields():
return list(SearchFields.objects.values_list('id', flat=True))
def nameSearchField():
return [SearchFields.objects.get(name='Name').id]
def set_default_search_vector(apps, schema_editor):

View File

@@ -2,7 +2,12 @@
from django_scopes import scopes_disabled
from django.db import migrations, models
from cookbook.models import nameSearchField
from cookbook.models import SearchFields
def nameSearchField():
return [SearchFields.objects.get(name='Name').id]
def add_default_trigram(apps, schema_editor):

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2022-03-04 13:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0172_ingredient_original_text'),
]
operations = [
migrations.AddField(
model_name='recipe',
name='source_url',
field=models.CharField(blank=True, default=None, max_length=1024, null=True),
),
]

View File

@@ -0,0 +1,45 @@
# Generated by Django 4.0.4 on 2022-05-31 14:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
from django_scopes import scopes_disabled
def migrate_space_permissions(apps, schema_editor):
with scopes_disabled():
UserPreference = apps.get_model('cookbook', 'UserPreference')
UserSpace = apps.get_model('cookbook', 'UserSpace')
for up in UserPreference.objects.exclude(space=None).all():
us = UserSpace.objects.create(user=up.user, space=up.space, active=True)
us.groups.set(up.user.groups.all())
class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cookbook', '0173_recipe_source_url'),
]
operations = [
migrations.AlterField(
model_name='food',
name='substitute',
field=models.ManyToManyField(blank=True, to='cookbook.food'),
),
migrations.CreateModel(
name='UserSpace',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('active', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('groups', models.ManyToManyField(to='auth.group')),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.RunPython(migrate_space_permissions)
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 4.0.4 on 2022-05-31 14:56
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0174_alter_food_substitute_userspace'),
]
operations = [
migrations.RemoveField(
model_name='userpreference',
name='space',
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 4.0.4 on 2022-06-14 14:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0175_remove_userpreference_space'),
]
operations = [
migrations.AlterField(
model_name='searchpreference',
name='icontains',
field=models.ManyToManyField(blank=True, related_name='icontains_fields', to='cookbook.searchfields'),
),
migrations.AlterField(
model_name='searchpreference',
name='trigram',
field=models.ManyToManyField(blank=True, related_name='trigram_fields', to='cookbook.searchfields'),
),
migrations.AlterField(
model_name='searchpreference',
name='unaccent',
field=models.ManyToManyField(blank=True, related_name='unaccent_fields', to='cookbook.searchfields'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2022-06-26 10:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0176_alter_searchpreference_icontains_and_more'),
]
operations = [
migrations.AddField(
model_name='recipe',
name='show_ingredient_overview',
field=models.BooleanField(default=True),
),
]

View File

@@ -2,9 +2,7 @@ import operator
import pathlib
import re
import uuid
from collections import OrderedDict
from datetime import date, timedelta
from decimal import Decimal
from annoying.fields import AutoOneToOneField
from django.contrib import auth
@@ -14,10 +12,9 @@ from django.contrib.postgres.search import SearchVectorField
from django.core.files.uploadedfile import InMemoryUploadedFile, UploadedFile
from django.core.validators import MinLengthValidator
from django.db import IntegrityError, models
from django.db.models import Index, ProtectedError, Q, Subquery
from django.db.models import Index, ProtectedError, Q
from django.db.models.fields.related import ManyToManyField
from django.db.models.functions import Substr
from django.db.transaction import atomic
from django.utils import timezone
from django.utils.translation import gettext as _
from django_prometheus.models import ExportModelOperationsMixin
@@ -35,6 +32,19 @@ def get_user_name(self):
return self.username
def get_active_space(self):
"""
Returns the active space of a user or in case no space is actives raises an *** exception
CAREFUL: cannot be used in django scopes with scope() function because passing None as a scope context means no space checking is enforced (at least I think)!!
:param self: user
:return: space currently active for user
"""
try:
return self.userspace_set.filter(active=True).first().space
except AttributeError:
return None
def get_shopping_share(self):
# get list of users that shared shopping list with user. Django ORM forbids this type of query, so raw is required
return User.objects.raw(' '.join([
@@ -49,6 +59,7 @@ def get_shopping_share(self):
auth.models.User.add_to_class('get_user_name', get_user_name)
auth.models.User.add_to_class('get_shopping_share', get_shopping_share)
auth.models.User.add_to_class('get_active_space', get_active_space)
def get_model_name(model):
@@ -241,9 +252,57 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
max_users = models.IntegerField(default=0)
allow_sharing = models.BooleanField(default=True)
demo = models.BooleanField(default=False)
food_inherit = models.ManyToManyField(FoodInheritField, blank=True)
food_inherit = models.ManyToManyField(FoodInheritField, blank=True)
show_facet_count = models.BooleanField(default=False)
def safe_delete(self):
"""
Safely deletes a space by deleting all objects belonging to the space first and then deleting the space itself
"""
CookLog.objects.filter(space=self).delete()
ViewLog.objects.filter(space=self).delete()
ImportLog.objects.filter(space=self).delete()
BookmarkletImport.objects.filter(space=self).delete()
CustomFilter.objects.filter(space=self).delete()
Comment.objects.filter(recipe__space=self).delete()
Keyword.objects.filter(space=self).delete()
Ingredient.objects.filter(space=self).delete()
Food.objects.filter(space=self).delete()
Unit.objects.filter(space=self).delete()
Step.objects.filter(space=self).delete()
NutritionInformation.objects.filter(space=self).delete()
RecipeBookEntry.objects.filter(book__space=self).delete()
RecipeBook.objects.filter(space=self).delete()
MealType.objects.filter(space=self).delete()
MealPlan.objects.filter(space=self).delete()
ShareLink.objects.filter(space=self).delete()
Recipe.objects.filter(space=self).delete()
RecipeImport.objects.filter(space=self).delete()
SyncLog.objects.filter(sync__space=self).delete()
Sync.objects.filter(space=self).delete()
Storage.objects.filter(space=self).delete()
ShoppingListEntry.objects.filter(shoppinglist__space=self).delete()
ShoppingListRecipe.objects.filter(shoppinglist__space=self).delete()
ShoppingList.objects.filter(space=self).delete()
SupermarketCategoryRelation.objects.filter(supermarket__space=self).delete()
SupermarketCategory.objects.filter(space=self).delete()
Supermarket.objects.filter(space=self).delete()
InviteLink.objects.filter(space=self).delete()
UserFile.objects.filter(space=self).delete()
Automation.objects.filter(space=self).delete()
self.delete()
def get_owner(self):
return self.created_by
def get_space(self):
return self
def __str__(self):
return self.name
@@ -337,16 +396,28 @@ class UserPreference(models.Model, PermissionModelMixin):
default_delay = models.DecimalField(default=4, max_digits=8, decimal_places=4)
shopping_recent_days = models.PositiveIntegerField(default=7)
csv_delim = models.CharField(max_length=2, default=",")
csv_prefix = models.CharField(max_length=10, blank=True,)
csv_prefix = models.CharField(max_length=10, blank=True, )
created_at = models.DateTimeField(auto_now_add=True)
space = models.ForeignKey(Space, on_delete=models.CASCADE, null=True)
objects = ScopedManager(space='space')
def __str__(self):
return str(self.user)
class UserSpace(models.Model, PermissionModelMixin):
user = models.ForeignKey(User, on_delete=models.CASCADE)
space = models.ForeignKey(Space, on_delete=models.CASCADE)
groups = models.ManyToManyField(Group)
# there should always only be one active space although permission methods are written in such a way
# that having more than one active space should just break certain parts of the application and not leak any data
active = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Storage(models.Model, PermissionModelMixin):
DROPBOX = 'DB'
NEXTCLOUD = 'NEXTCLOUD'
@@ -496,11 +567,11 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
ignore_shopping = models.BooleanField(default=False) # inherited field
onhand_users = models.ManyToManyField(User, blank=True)
description = models.TextField(default='', blank=True)
inherit_fields = models.ManyToManyField(FoodInheritField, blank=True)
inherit_fields = models.ManyToManyField(FoodInheritField, blank=True)
substitute = models.ManyToManyField("self", blank=True)
substitute_siblings = models.BooleanField(default=False)
substitute_children = models.BooleanField(default=False)
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
child_inherit_fields = models.ManyToManyField(FoodInheritField, blank=True, related_name='child_inherit')
space = models.ForeignKey(Space, on_delete=models.CASCADE)
objects = ScopedManager(space='space', _manager_class=TreeManager)
@@ -533,20 +604,21 @@ class Food(ExportModelOperationsMixin('food'), TreeModel, PermissionModelMixin):
if food:
# if child inherit fields is preset children should be set to that, otherwise inherit this foods inherited fields
inherit = list((food.child_inherit_fields.all() or food.inherit_fields.all()).values('id', 'field'))
tree_filter = Q(path__startswith=food.path, space=space, depth=food.depth+1)
tree_filter = Q(path__startswith=food.path, space=space, depth=food.depth + 1)
else:
inherit = list(space.food_inherit.all().values('id', 'field'))
tree_filter = Q(space=space)
# remove all inherited fields from food
Through = Food.objects.filter(tree_filter).first().inherit_fields.through
Through.objects.all().delete()
trough = Food.inherit_fields.through
trough.objects.all().delete()
# food is going to inherit attributes
if len(inherit) > 0:
# ManyToMany cannot be updated through an UPDATE operation
for i in inherit:
Through.objects.bulk_create([
Through(food_id=x, foodinheritfield_id=i['id'])
trough.objects.bulk_create([
trough(food_id=x, foodinheritfield_id=i['id'])
for x in Food.objects.filter(tree_filter).values_list('id', flat=True)
])
@@ -593,6 +665,8 @@ class Ingredient(ExportModelOperationsMixin('ingredient'), models.Model, Permiss
order = models.IntegerField(default=0)
original_text = models.CharField(max_length=512, null=True, blank=True, default=None)
original_text = models.CharField(max_length=512, null=True, blank=True, default=None)
space = models.ForeignKey(Space, on_delete=models.CASCADE)
objects = ScopedManager(space='space')
@@ -663,9 +737,7 @@ class Recipe(ExportModelOperationsMixin('recipe'), models.Model, PermissionModel
servings = models.IntegerField(default=1)
servings_text = models.CharField(default='', blank=True, max_length=32)
image = models.ImageField(upload_to='recipes/', blank=True, null=True)
storage = models.ForeignKey(
Storage, on_delete=models.PROTECT, blank=True, null=True
)
storage = models.ForeignKey(Storage, on_delete=models.PROTECT, blank=True, null=True)
file_uid = models.CharField(max_length=256, default="", blank=True)
file_path = models.CharField(max_length=512, default="", blank=True)
link = models.CharField(max_length=512, null=True, blank=True)
@@ -675,9 +747,10 @@ class Recipe(ExportModelOperationsMixin('recipe'), models.Model, PermissionModel
working_time = models.IntegerField(default=0)
waiting_time = models.IntegerField(default=0)
internal = models.BooleanField(default=False)
nutrition = models.ForeignKey(
NutritionInformation, blank=True, null=True, on_delete=models.CASCADE
)
nutrition = models.ForeignKey(NutritionInformation, blank=True, null=True, on_delete=models.CASCADE)
show_ingredient_overview = models.BooleanField(default=True)
source_url = models.CharField(max_length=1024, default=None, blank=True, null=True)
created_by = models.ForeignKey(User, on_delete=models.PROTECT)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -1078,14 +1151,6 @@ class SearchFields(models.Model, PermissionModelMixin):
return _(self.name)
def allSearchFields():
return list(SearchFields.objects.values_list('id', flat=True))
def nameSearchField():
return [SearchFields.objects.get(name='Name').id]
class SearchPreference(models.Model, PermissionModelMixin):
# Search Style (validation parsleyjs.org)
# phrase or plain or raw (websearch and trigrams are mutually exclusive)
@@ -1104,10 +1169,10 @@ class SearchPreference(models.Model, PermissionModelMixin):
search = models.CharField(choices=SEARCH_STYLE, max_length=32, default=SIMPLE)
lookup = models.BooleanField(default=False)
unaccent = models.ManyToManyField(SearchFields, related_name="unaccent_fields", blank=True, default=allSearchFields)
icontains = models.ManyToManyField(SearchFields, related_name="icontains_fields", blank=True, default=nameSearchField)
unaccent = models.ManyToManyField(SearchFields, related_name="unaccent_fields", blank=True)
icontains = models.ManyToManyField(SearchFields, related_name="icontains_fields", blank=True)
istartswith = models.ManyToManyField(SearchFields, related_name="istartswith_fields", blank=True)
trigram = models.ManyToManyField(SearchFields, related_name="trigram_fields", blank=True, default=nameSearchField)
trigram = models.ManyToManyField(SearchFields, related_name="trigram_fields", blank=True)
fulltext = models.ManyToManyField(SearchFields, related_name="fulltext_fields", blank=True)
trigram_threshold = models.DecimalField(default=0.2, decimal_places=2, max_digits=3)

View File

@@ -4,6 +4,8 @@ import os
from datetime import datetime
import requests
import validators
from cookbook.models import Recipe, RecipeImport, SyncLog
from cookbook.provider.provider import Provider
@@ -104,9 +106,11 @@ class Dropbox(Provider):
recipe.link = Dropbox.get_share_link(recipe)
recipe.save()
response = requests.get(recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.'))
url = recipe.link.replace('www.dropbox.', 'dl.dropboxusercontent.')
if validators.url(url, public=True):
response = requests.get(url)
return io.BytesIO(response.content)
return io.BytesIO(response.content)
@staticmethod
def rename_file(recipe, new_name):

View File

@@ -4,6 +4,7 @@ import tempfile
from datetime import datetime
import requests
import validators
import webdav3.client as wc
from cookbook.models import Recipe, RecipeImport, SyncLog
from cookbook.provider.provider import Provider
@@ -92,20 +93,21 @@ class Nextcloud(Provider):
"Content-Type": "application/json"
}
r = requests.get(
url,
headers=headers,
auth=HTTPBasicAuth(
recipe.storage.username, recipe.storage.password
if validators.url(url, public=True):
r = requests.get(
url,
headers=headers,
auth=HTTPBasicAuth(
recipe.storage.username, recipe.storage.password
)
)
)
response_json = r.json()
for element in response_json['ocs']['data']:
if element['share_type'] == '3':
return element['url']
response_json = r.json()
for element in response_json['ocs']['data']:
if element['share_type'] == '3':
return element['url']
return Nextcloud.create_share_link(recipe)
return Nextcloud.create_share_link(recipe)
@staticmethod
def get_file(recipe):

View File

@@ -1,26 +1,35 @@
from datetime import timedelta
import traceback
from datetime import datetime, timedelta
from decimal import Decimal
from gettext import gettext as _
from html import escape
from smtplib import SMTPException
from django.contrib.auth.models import User
from django.contrib.auth.models import Group, User
from django.core.mail import send_mail
from django.db.models import Avg, Q, QuerySet, Sum
from django.http import BadHeaderError
from django.urls import reverse
from django.utils import timezone
from django_scopes import scopes_disabled
from drf_writable_nested import UniqueFieldsMixin, WritableNestedModelSerializer
from PIL import Image
from rest_framework import serializers
from rest_framework.exceptions import NotFound, ValidationError
from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
from cookbook.helper.HelperFunctions import str2bool
from cookbook.helper.permission_helper import above_space_limit
from cookbook.helper.shopping_helper import RecipeShoppingEditor
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, CustomFilter,
ExportLog, Food, FoodInheritField, ImportLog, Ingredient, Keyword,
MealPlan, MealType, NutritionInformation, Recipe, RecipeBook,
ExportLog, Food, FoodInheritField, ImportLog, Ingredient, InviteLink,
Keyword, MealPlan, MealType, NutritionInformation, Recipe, RecipeBook,
RecipeBookEntry, RecipeImport, ShareLink, ShoppingList,
ShoppingListEntry, ShoppingListRecipe, Step, Storage, Supermarket,
SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, Unit,
UserFile, UserPreference, ViewLog)
ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage,
Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync,
SyncLog, Unit, UserFile, UserPreference, UserSpace, ViewLog)
from cookbook.templatetags.custom_tags import markdown
from recipes.settings import MEDIA_URL
from recipes.settings import AWS_ENABLED, MEDIA_URL
class ExtendedRecipeMixin(serializers.ModelSerializer):
@@ -41,7 +50,8 @@ class ExtendedRecipeMixin(serializers.ModelSerializer):
api_serializer = None
# extended values are computationally expensive and not needed in normal circumstances
try:
if str2bool(self.context['request'].query_params.get('extended', False)) and self.__class__ == api_serializer:
if str2bool(
self.context['request'].query_params.get('extended', False)) and self.__class__ == api_serializer:
return fields
except (AttributeError, KeyError) as e:
pass
@@ -54,7 +64,12 @@ class ExtendedRecipeMixin(serializers.ModelSerializer):
def get_image(self, obj):
if obj.recipe_image:
return MEDIA_URL + obj.recipe_image
if AWS_ENABLED:
storage = CachedS3Boto3Storage()
path = storage.url(obj.recipe_image)
else:
path = MEDIA_URL + obj.recipe_image
return path
class CustomDecimalField(serializers.Field):
@@ -90,7 +105,8 @@ class CustomOnHandField(serializers.Field):
shared_users = getattr(request, '_shared_users', None)
if shared_users is None:
try:
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [self.context['request'].user.id]
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [
self.context['request'].user.id]
except AttributeError: # Anonymous users (using share links) don't have shared users
shared_users = []
return obj.onhand_users.filter(id__in=shared_users).exists()
@@ -108,12 +124,98 @@ class SpaceFilterSerializer(serializers.ListSerializer):
# if query is sliced it came from api request not nested serializer
return super().to_representation(data)
if self.child.Meta.model == User:
data = data.filter(userpreference__space=self.context['request'].space)
data = data.filter(userspace__space=self.context['request'].user.get_active_space()).all()
else:
data = data.filter(**{'__'.join(data.model.get_space_key()): self.context['request'].space})
return super().to_representation(data)
class UserNameSerializer(WritableNestedModelSerializer):
username = serializers.SerializerMethodField('get_user_label')
def get_user_label(self, obj):
return obj.get_user_name()
class Meta:
list_serializer_class = SpaceFilterSerializer
model = User
fields = ('id', 'username')
class GroupSerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
def update(self, instance, validated_data):
return instance # cannot update group
class Meta:
model = Group
fields = ('id', 'name')
class FoodInheritFieldSerializer(UniqueFieldsMixin, WritableNestedModelSerializer):
name = serializers.CharField(allow_null=True, allow_blank=True, required=False)
field = serializers.CharField(allow_null=True, allow_blank=True, required=False)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
def update(self, instance, validated_data):
return instance
class Meta:
model = FoodInheritField
fields = ('id', 'name', 'field',)
read_only_fields = ['id']
class SpaceSerializer(WritableNestedModelSerializer):
user_count = serializers.SerializerMethodField('get_user_count')
recipe_count = serializers.SerializerMethodField('get_recipe_count')
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
food_inherit = FoodInheritFieldSerializer(many=True)
def get_user_count(self, obj):
return UserSpace.objects.filter(space=obj).count()
def get_recipe_count(self, obj):
return Recipe.objects.filter(space=obj).count()
def get_file_size_mb(self, obj):
try:
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
except TypeError:
return 0
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = Space
fields = ('id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb',)
read_only_fields = ('id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo',)
class UserSpaceSerializer(WritableNestedModelSerializer):
user = UserNameSerializer(read_only=True)
groups = GroupSerializer(many=True)
def validate(self, data):
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
return super().validate(data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserSpace
fields = ('id', 'user', 'space', 'groups', 'active', 'created_at', 'updated_at',)
read_only_fields = ('id', 'created_at', 'updated_at', 'space')
class SpacedModelSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
@@ -133,64 +235,54 @@ class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
read_only_fields = ('created_by',)
class UserNameSerializer(WritableNestedModelSerializer):
username = serializers.SerializerMethodField('get_user_label')
def get_user_label(self, obj):
return obj.get_user_name()
class Meta:
list_serializer_class = SpaceFilterSerializer
model = User
fields = ('id', 'username')
class FoodInheritFieldSerializer(WritableNestedModelSerializer):
name = serializers.CharField(allow_null=True, allow_blank=True, required=False)
field = serializers.CharField(allow_null=True, allow_blank=True, required=False)
def create(self, validated_data):
# don't allow writing to FoodInheritField via API
return FoodInheritField.objects.get(**validated_data)
def update(self, instance, validated_data):
# don't allow writing to FoodInheritField via API
return FoodInheritField.objects.get(**validated_data)
class Meta:
model = FoodInheritField
fields = ('id', 'name', 'field',)
read_only_fields = ['id']
class UserPreferenceSerializer(WritableNestedModelSerializer):
food_inherit_default = FoodInheritFieldSerializer(source='space.food_inherit', many=True, allow_null=True, required=False, read_only=True)
plan_share = UserNameSerializer(many=True, allow_null=True, required=False, read_only=True)
food_inherit_default = serializers.SerializerMethodField('get_food_inherit_defaults')
plan_share = UserNameSerializer(many=True, allow_null=True, required=False)
shopping_share = UserNameSerializer(many=True, allow_null=True, required=False)
food_children_exist = serializers.SerializerMethodField('get_food_children_exist')
def get_food_inherit_defaults(self, obj):
return FoodInheritFieldSerializer(obj.user.get_active_space().food_inherit.all(), many=True).data
def get_food_children_exist(self, obj):
space = getattr(self.context.get('request', None), 'space', None)
return Food.objects.filter(depth__gt=0, space=space).exists()
def update(self, instance, validated_data):
with scopes_disabled():
return super().update(instance, validated_data)
def create(self, validated_data):
if not validated_data.get('user', None):
raise ValidationError(_('A user is required'))
if (validated_data['user'] != self.context['request'].user):
raise NotFound()
return super().create(validated_data)
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserPreference
fields = (
'user', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj', 'search_style', 'show_recent', 'plan_share',
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping', 'food_inherit_default', 'default_delay',
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days', 'csv_delim', 'csv_prefix',
'user', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj', 'search_style',
'show_recent', 'plan_share',
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping',
'food_inherit_default', 'default_delay',
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days',
'csv_delim', 'csv_prefix',
'filter_to_supermarket', 'shopping_add_onhand', 'left_handed', 'food_children_exist'
)
class UserFileSerializer(serializers.ModelSerializer):
file = serializers.FileField(write_only=True)
file_download = serializers.SerializerMethodField('get_download_link')
preview = serializers.SerializerMethodField('get_preview_link')
def get_download_link(self, obj):
return self.context['request'].build_absolute_uri(reverse('api_download_file', args={obj.pk}))
def get_preview_link(self, obj):
try:
img = Image.open(obj.file.file.file)
return self.context['request'].build_absolute_uri(obj.file.url)
except Exception:
traceback.print_exc()
return ""
def check_file_limit(self, validated_data):
if 'file' in validated_data:
@@ -220,12 +312,25 @@ class UserFileSerializer(serializers.ModelSerializer):
class Meta:
model = UserFile
fields = ('name', 'file', 'file_size_kb', 'id',)
fields = ('id', 'name', 'file', 'file_download', 'preview', 'file_size_kb')
read_only_fields = ('id', 'file_size_kb')
extra_kwargs = {"file": {"required": False, }}
class UserFileViewSerializer(serializers.ModelSerializer):
file_download = serializers.SerializerMethodField('get_download_link')
preview = serializers.SerializerMethodField('get_preview_link')
def get_download_link(self, obj):
return self.context['request'].build_absolute_uri(reverse('api_download_file', args={obj.pk}))
def get_preview_link(self, obj):
try:
img = Image.open(obj.file.file.file)
return self.context['request'].build_absolute_uri(obj.file.url)
except Exception:
traceback.print_exc()
return ""
def create(self, validated_data):
raise ValidationError('Cannot create File over this view')
@@ -235,7 +340,7 @@ class UserFileViewSerializer(serializers.ModelSerializer):
class Meta:
model = UserFile
fields = ('name', 'file', 'id',)
fields = ('id', 'name', 'file_download', 'preview')
read_only_fields = ('id', 'file')
@@ -364,23 +469,29 @@ class SupermarketSerializer(UniqueFieldsMixin, SpacedModelSerializer):
fields = ('id', 'name', 'description', 'category_to_supermarket')
class RecipeSimpleSerializer(serializers.ModelSerializer):
class RecipeSimpleSerializer(WritableNestedModelSerializer):
url = serializers.SerializerMethodField('get_url')
def get_url(self, obj):
return reverse('view_recipe', args=[obj.id])
def create(self, validated_data):
# don't allow writing to Recipe via this API
return Recipe.objects.get(**validated_data)
def update(self, instance, validated_data):
# don't allow writing to Recipe via this API
return Recipe.objects.get(**validated_data)
class Meta:
model = Recipe
fields = ('id', 'name', 'url')
read_only_fields = ['id', 'name', 'url']
class FoodSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Food
fields = ('id', 'name')
read_only_fields = ['id', 'name']
class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedRecipeMixin):
@@ -403,7 +514,8 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
shared_users = getattr(request, '_shared_users', None)
if shared_users is None:
try:
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [self.context['request'].user.id]
shared_users = [x.id for x in list(self.context['request'].user.get_shopping_share())] + [
self.context['request'].user.id]
except AttributeError:
shared_users = []
filter = Q(id__in=obj.substitute.all())
@@ -427,6 +539,8 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
name=sc_name,
space=space, defaults=sm_category)
onhand = validated_data.pop('food_onhand', None)
if recipe := validated_data.get('recipe', None):
validated_data['recipe'] = Recipe.objects.get(**recipe)
# assuming if on hand for user also onhand for shopping_share users
if not onhand is None:
@@ -472,11 +586,15 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR
read_only_fields = ('id', 'numchild', 'parent', 'image', 'numrecipe')
class IngredientSerializer(WritableNestedModelSerializer):
food = FoodSerializer(allow_null=True)
class IngredientSimpleSerializer(WritableNestedModelSerializer):
food = FoodSimpleSerializer(allow_null=True)
unit = UnitSerializer(allow_null=True)
used_in_recipes = serializers.SerializerMethodField('get_used_in_recipes')
amount = CustomDecimalField()
def get_used_in_recipes(self, obj):
return list(Recipe.objects.filter(steps__ingredients=obj.id).values('id', 'name'))
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
@@ -489,10 +607,14 @@ class IngredientSerializer(WritableNestedModelSerializer):
model = Ingredient
fields = (
'id', 'food', 'unit', 'amount', 'note', 'order',
'is_header', 'no_amount', 'original_text'
'is_header', 'no_amount', 'original_text', 'used_in_recipes',
)
class IngredientSerializer(IngredientSimpleSerializer):
food = FoodSerializer(allow_null=True)
class StepSerializer(WritableNestedModelSerializer, ExtendedRecipeMixin):
ingredients = IngredientSerializer(many=True)
ingredients_markdown = serializers.SerializerMethodField('get_ingredients_markdown')
@@ -615,11 +737,17 @@ class RecipeSerializer(RecipeBaseSerializer):
model = Recipe
fields = (
'id', 'name', 'description', 'image', 'keywords', 'steps', 'working_time',
'waiting_time', 'created_by', 'created_at', 'updated_at',
'internal', 'nutrition', 'servings', 'file_path', 'servings_text', 'rating', 'last_cooked',
'waiting_time', 'created_by', 'created_at', 'updated_at', 'source_url',
'internal', 'show_ingredient_overview', 'nutrition', 'servings', 'file_path', 'servings_text', 'rating', 'last_cooked',
)
read_only_fields = ['image', 'created_by', 'created_at']
def validate(self, data):
above_limit, msg = above_space_limit(self.context['request'].space)
if above_limit:
raise serializers.ValidationError(msg)
return super().validate(data)
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].space
@@ -627,9 +755,12 @@ class RecipeSerializer(RecipeBaseSerializer):
class RecipeImageSerializer(WritableNestedModelSerializer):
image = serializers.ImageField(required=False, allow_null=True)
image_url = serializers.CharField(max_length=4096, required=False, allow_null=True)
class Meta:
model = Recipe
fields = ['image', ]
fields = ['image', 'image_url', ]
class RecipeImportSerializer(SpacedModelSerializer):
@@ -684,7 +815,8 @@ class RecipeBookEntrySerializer(serializers.ModelSerializer):
def create(self, validated_data):
book = validated_data['book']
recipe = validated_data['recipe']
if not book.get_owner() == self.context['request'].user and not self.context['request'].user in book.get_shared():
if not book.get_owner() == self.context['request'].user and not self.context[
'request'].user in book.get_shared():
raise NotFound(detail=None, code=None)
obj, created = RecipeBookEntry.objects.get_or_create(book=book, recipe=recipe)
return obj
@@ -713,7 +845,7 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
mealplan = super().create(validated_data)
if self.context['request'].data.get('addshopping', False):
if self.context['request'].data.get('addshopping', False) and self.context['request'].data.get('recipe', None):
SLR = RecipeShoppingEditor(user=validated_data['created_by'], space=validated_data['space'])
SLR.create(mealplan=mealplan, servings=validated_data['servings'])
return mealplan
@@ -737,7 +869,8 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer):
def get_name(self, obj):
if not isinstance(value := obj.servings, Decimal):
value = Decimal(value)
value = value.quantize(Decimal(1)) if value == value.to_integral() else value.normalize() # strips trailing zero
value = value.quantize(
Decimal(1)) if value == value.to_integral() else value.normalize() # strips trailing zero
return (
obj.name
or getattr(obj.mealplan, 'title', None)
@@ -814,7 +947,8 @@ class ShoppingListEntrySerializer(WritableNestedModelSerializer):
class Meta:
model = ShoppingListEntry
fields = (
'id', 'list_recipe', 'food', 'unit', 'ingredient', 'ingredient_note', 'amount', 'order', 'checked', 'recipe_mealplan',
'id', 'list_recipe', 'food', 'unit', 'ingredient', 'ingredient_note', 'amount', 'order', 'checked',
'recipe_mealplan',
'created_by', 'created_at', 'completed_at', 'delay_until'
)
read_only_fields = ('id', 'created_by', 'created_at',)
@@ -912,7 +1046,10 @@ class ExportLogSerializer(serializers.ModelSerializer):
class Meta:
model = ExportLog
fields = ('id', 'type', 'msg', 'running', 'total_recipes', 'exported_recipes', 'cache_duration', 'possibly_not_expired', 'created_by', 'created_at')
fields = (
'id', 'type', 'msg', 'running', 'total_recipes', 'exported_recipes', 'cache_duration',
'possibly_not_expired',
'created_by', 'created_at')
read_only_fields = ('created_by',)
@@ -930,15 +1067,59 @@ class AutomationSerializer(serializers.ModelSerializer):
read_only_fields = ('created_by',)
class InviteLinkSerializer(WritableNestedModelSerializer):
group = GroupSerializer()
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].space
obj = super().create(validated_data)
if obj.email:
try:
if InviteLink.objects.filter(space=self.context['request'].space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20:
message = _('Hello') + '!\n\n' + _('You have been invited by ') + escape(self.context['request'].user.username)
message += _(' to join their Tandoor Recipes space ') + escape(self.context['request'].space.name) + '.\n\n'
message += _('Click the following link to activate your account: ') + self.context['request'].build_absolute_uri(reverse('view_invite', args=[str(obj.uuid)])) + '\n\n'
message += _('If the link does not work use the following code to manually join the space: ') + str(obj.uuid) + '\n\n'
message += _('The invitation is valid until ') + str(obj.valid_until) + '\n\n'
message += _('Tandoor Recipes is an Open Source recipe manager. Check it out on GitHub ') + 'https://github.com/vabene1111/recipes/'
send_mail(
_('Tandoor Recipes Invite'),
message,
None,
[obj.email],
fail_silently=True,
)
except (SMTPException, BadHeaderError, TimeoutError):
pass
return obj
class Meta:
model = InviteLink
fields = (
'id', 'uuid', 'email', 'group', 'valid_until', 'used_by', 'created_by', 'created_at',)
read_only_fields = ('id', 'uuid', 'created_by', 'created_at',)
# CORS, REST and Scopes aren't currently working
# Scopes are evaluating before REST has authenticated the user assigning a None space
# I've made the change below to fix the bookmarklet, other serializers likely need a similar/better fix
class BookmarkletImportSerializer(serializers.ModelSerializer):
class BookmarkletImportListSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].user.userpreference.space
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
class Meta:
model = BookmarkletImport
fields = ('id', 'url', 'created_by', 'created_at')
read_only_fields = ('created_by', 'space')
class BookmarkletImportSerializer(BookmarkletImportListSerializer):
class Meta:
model = BookmarkletImport
fields = ('id', 'url', 'html', 'created_by', 'created_at')
@@ -1024,10 +1205,12 @@ class RecipeExportSerializer(WritableNestedModelSerializer):
class RecipeShoppingUpdateSerializer(serializers.ModelSerializer):
list_recipe = serializers.IntegerField(write_only=True, allow_null=True, required=False, help_text=_("Existing shopping list to update"))
list_recipe = serializers.IntegerField(write_only=True, allow_null=True, required=False,
help_text=_("Existing shopping list to update"))
ingredients = serializers.IntegerField(write_only=True, allow_null=True, required=False, help_text=_(
"List of ingredient IDs from the recipe to add, if not provided all ingredients will be added."))
servings = serializers.IntegerField(default=1, write_only=True, allow_null=True, required=False, help_text=_("Providing a list_recipe ID and servings of 0 will delete that shopping list."))
servings = serializers.IntegerField(default=1, write_only=True, allow_null=True, required=False, help_text=_(
"Providing a list_recipe ID and servings of 0 will delete that shopping list."))
class Meta:
model = Recipe
@@ -1035,10 +1218,21 @@ class RecipeShoppingUpdateSerializer(serializers.ModelSerializer):
class FoodShoppingUpdateSerializer(serializers.ModelSerializer):
amount = serializers.IntegerField(write_only=True, allow_null=True, required=False, help_text=_("Amount of food to add to the shopping list"))
unit = serializers.IntegerField(write_only=True, allow_null=True, required=False, help_text=_("ID of unit to use for the shopping list"))
delete = serializers.ChoiceField(choices=['true'], write_only=True, allow_null=True, allow_blank=True, help_text=_("When set to true will delete all food from active shopping lists."))
amount = serializers.IntegerField(write_only=True, allow_null=True, required=False,
help_text=_("Amount of food to add to the shopping list"))
unit = serializers.IntegerField(write_only=True, allow_null=True, required=False,
help_text=_("ID of unit to use for the shopping list"))
delete = serializers.ChoiceField(choices=['true'], write_only=True, allow_null=True, allow_blank=True,
help_text=_("When set to true will delete all food from active shopping lists."))
class Meta:
model = Recipe
fields = ['id', 'amount', 'unit', 'delete', ]
# non model serializers
class RecipeFromSourceSerializer(serializers.Serializer):
url = serializers.CharField(max_length=4096, required=False, allow_null=True, allow_blank=True)
data = serializers.CharField(required=False, allow_null=True, allow_blank=True)
bookmarklet = serializers.IntegerField(required=False, allow_null=True, )

View File

@@ -2,16 +2,17 @@ from decimal import Decimal
from functools import wraps
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.postgres.search import SearchVector
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils import translation
from django_scopes import scope
from django_scopes import scope, scopes_disabled
from cookbook.helper.shopping_helper import RecipeShoppingEditor
from cookbook.managers import DICTIONARY
from cookbook.models import (Food, FoodInheritField, Ingredient, MealPlan, Recipe,
ShoppingListEntry, Step)
ShoppingListEntry, Step, UserPreference, SearchPreference, SearchFields)
SQLITE = True
if settings.DATABASES['default']['ENGINE'] in ['django.db.backends.postgresql_psycopg2',
@@ -28,9 +29,26 @@ def skip_signal(signal_func):
if hasattr(instance, 'skip_signal'):
return None
return signal_func(sender, instance, **kwargs)
return _decorator
@receiver(post_save, sender=User)
def create_user_preference(sender, instance=None, created=False, **kwargs):
if created:
with scopes_disabled():
UserPreference.objects.get_or_create(user=instance)
@receiver(post_save, sender=SearchPreference)
def create_search_preference(sender, instance=None, created=False, **kwargs):
if created:
with scopes_disabled():
instance.unaccent.add(SearchFields.objects.get(name='Name'))
instance.icontains.add(SearchFields.objects.get(name='Name'))
instance.trigram.add(SearchFields.objects.get(name='Name'))
@receiver(post_save, sender=Recipe)
@skip_signal
def update_recipe_search_vector(sender, instance=None, created=False, **kwargs):
@@ -104,21 +122,30 @@ def update_food_inheritance(sender, instance=None, created=False, **kwargs):
@receiver(post_save, sender=MealPlan)
def auto_add_shopping(sender, instance=None, created=False, weak=False, **kwargs):
print("MEAL_AUTO_ADD Signal trying to auto add to shopping")
if not instance:
return
user = instance.get_owner()
with scope(space=instance.space):
slr_exists = instance.shoppinglistrecipe_set.exists()
if not created and slr_exists:
for x in instance.shoppinglistrecipe_set.all():
# assuming that permissions checks for the MealPlan have happened upstream
if instance.servings != x.servings:
SLR = RecipeShoppingEditor(id=x.id, user=user, space=instance.space)
SLR.edit_servings(servings=instance.servings)
elif not user.userpreference.mealplan_autoadd_shopping or not instance.recipe:
print("MEAL_AUTO_ADD Instance is none")
return
if created:
SLR = RecipeShoppingEditor(user=user, space=instance.space)
SLR.create(mealplan=instance, servings=instance.servings)
try:
space = instance.get_space()
user = instance.get_owner()
with scope(space=space):
slr_exists = instance.shoppinglistrecipe_set.exists()
if not created and slr_exists:
for x in instance.shoppinglistrecipe_set.all():
# assuming that permissions checks for the MealPlan have happened upstream
if instance.servings != x.servings:
SLR = RecipeShoppingEditor(id=x.id, user=user, space=instance.space)
SLR.edit_servings(servings=instance.servings)
elif not user.userpreference.mealplan_autoadd_shopping or not instance.recipe:
print("MEAL_AUTO_ADD No recipe or no setting")
return
if created:
SLR = RecipeShoppingEditor(user=user, space=space)
SLR.create(mealplan=instance, servings=instance.servings)
print("MEAL_AUTO_ADD Created SLR")
except AttributeError:
pass

View File

@@ -1,3 +1,15 @@
.brand-icon {
height: 40px;
}
@media (max-width: 991.98px) {
.menu-dropdown-text {
font-size: 14px;
font-weight: 200;
}
}
.spinner-tandoor {
animation: rotation 3s infinite linear;
content: url("../assets/spinner.svg");

Some files were not shown because too many files have changed in this diff Show More