From 398b41ed23f38cbd9092005888e649deed0fdda1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2025 21:48:47 +1100 Subject: [PATCH 01/45] fix(deps): update dependency openai to v1.59.6 (#4872) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index a2962ef77..b96f5247a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1590,13 +1590,13 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openai" -version = "1.59.5" +version = "1.59.6" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" files = [ - {file = "openai-1.59.5-py3-none-any.whl", hash = "sha256:e646b44856b0dda9345d3c43639e056334d792d1690e99690313c0ef7ca4d8cc"}, - {file = "openai-1.59.5.tar.gz", hash = "sha256:9886e77c02dad9dc6a7b67a11ab372a56842a9b5d376aa476672175ab10e83a0"}, + {file = "openai-1.59.6-py3-none-any.whl", hash = "sha256:b28ed44eee3d5ebe1a3ea045ee1b4b50fea36ecd50741aaa5ce5a5559c900cb6"}, + {file = "openai-1.59.6.tar.gz", hash = "sha256:c7670727c2f1e4473f62fea6fa51475c8bc098c9ffb47bfb9eef5be23c747934"}, ] [package.dependencies] From 2be4bd1f7c0d26da3e8e342cad1bab7cf20e38f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 11 Jan 2025 10:58:59 +0000 Subject: [PATCH 02/45] fix(deps): update dependency sqlalchemy to v2.0.37 (#4873) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 118 ++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/poetry.lock b/poetry.lock index b96f5247a..3da9f6aac 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2908,72 +2908,72 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.36" +version = "2.0.37" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"}, - {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"}, - {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e"}, - {file = "SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436"}, - {file = "SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-win32.whl", hash = "sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c"}, - {file = "SQLAlchemy-2.0.36-cp37-cp37m-win_amd64.whl", hash = "sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-win32.whl", hash = "sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e"}, - {file = "SQLAlchemy-2.0.36-cp38-cp38-win_amd64.whl", hash = "sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-win32.whl", hash = "sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28"}, - {file = "SQLAlchemy-2.0.36-cp39-cp39-win_amd64.whl", hash = "sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a"}, - {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"}, - {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da36c3b0e891808a7542c5c89f224520b9a16c7f5e4d6a1156955605e54aef0e"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e7402ff96e2b073a98ef6d6142796426d705addd27b9d26c3b32dbaa06d7d069"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f5d254a22394847245f411a2956976401e84da4288aa70cbcd5190744062c1"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41296bbcaa55ef5fdd32389a35c710133b097f7b2609d8218c0eabded43a1d84"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bedee60385c1c0411378cbd4dc486362f5ee88deceea50002772912d798bb00f"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6c67415258f9f3c69867ec02fea1bf6508153709ecbd731a982442a590f2b7e4"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-win32.whl", hash = "sha256:650dcb70739957a492ad8acff65d099a9586b9b8920e3507ca61ec3ce650bb72"}, + {file = "SQLAlchemy-2.0.37-cp310-cp310-win_amd64.whl", hash = "sha256:93d1543cd8359040c02b6614421c8e10cd7a788c40047dbc507ed46c29ae5636"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:78361be6dc9073ed17ab380985d1e45e48a642313ab68ab6afa2457354ff692c"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b661b49d0cb0ab311a189b31e25576b7ac3e20783beb1e1817d72d9d02508bf5"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d57bafbab289e147d064ffbd5cca2d7b1394b63417c0636cea1f2e93d16eb9e8"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa2c0913f02341d25fb858e4fb2031e6b0813494cca1ba07d417674128ce11b"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9df21b8d9e5c136ea6cde1c50d2b1c29a2b5ff2b1d610165c23ff250e0704087"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db18ff6b8c0f1917f8b20f8eca35c28bbccb9f83afa94743e03d40203ed83de9"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-win32.whl", hash = "sha256:46954173612617a99a64aee103bcd3f078901b9a8dcfc6ae80cbf34ba23df989"}, + {file = "SQLAlchemy-2.0.37-cp311-cp311-win_amd64.whl", hash = "sha256:7b7e772dc4bc507fdec4ee20182f15bd60d2a84f1e087a8accf5b5b7a0dcf2ba"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2952748ecd67ed3b56773c185e85fc084f6bdcdec10e5032a7c25a6bc7d682ef"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3151822aa1db0eb5afd65ccfafebe0ef5cda3a7701a279c8d0bf17781a793bb4"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eaa8039b6d20137a4e02603aba37d12cd2dde7887500b8855356682fc33933f4"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cdba1f73b64530c47b27118b7053b8447e6d6f3c8104e3ac59f3d40c33aa9fd"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1b2690456528a87234a75d1a1644cdb330a6926f455403c8e4f6cad6921f9098"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf5ae8a9dcf657fd72144a7fd01f243236ea39e7344e579a121c4205aedf07bb"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-win32.whl", hash = "sha256:ea308cec940905ba008291d93619d92edaf83232ec85fbd514dcb329f3192761"}, + {file = "SQLAlchemy-2.0.37-cp312-cp312-win_amd64.whl", hash = "sha256:635d8a21577341dfe4f7fa59ec394b346da12420b86624a69e466d446de16aff"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8c4096727193762e72ce9437e2a86a110cf081241919ce3fab8e89c02f6b6658"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e4fb5ac86d8fe8151966814f6720996430462e633d225497566b3996966b9bdb"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e56a139bfe136a22c438478a86f8204c1eb5eed36f4e15c4224e4b9db01cb3e4"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f95fc8e3f34b5f6b3effb49d10ac97c569ec8e32f985612d9b25dd12d0d2e94"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c505edd429abdfe3643fa3b2e83efb3445a34a9dc49d5f692dd087be966020e0"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:12b0f1ec623cccf058cf21cb544f0e74656618165b083d78145cafde156ea7b6"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-win32.whl", hash = "sha256:293f9ade06b2e68dd03cfb14d49202fac47b7bb94bffcff174568c951fbc7af2"}, + {file = "SQLAlchemy-2.0.37-cp313-cp313-win_amd64.whl", hash = "sha256:d70f53a0646cc418ca4853da57cf3ddddbccb8c98406791f24426f2dd77fd0e2"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44f569d0b1eb82301b92b72085583277316e7367e038d97c3a1a899d9a05e342"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2eae3423e538c10d93ae3e87788c6a84658c3ed6db62e6a61bb9495b0ad16bb"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfff7be361048244c3aa0f60b5e63221c5e0f0e509f4e47b8910e22b57d10ae7"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:5bc3339db84c5fb9130ac0e2f20347ee77b5dd2596ba327ce0d399752f4fce39"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:84b9f23b0fa98a6a4b99d73989350a94e4a4ec476b9a7dfe9b79ba5939f5e80b"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-win32.whl", hash = "sha256:51bc9cfef83e0ac84f86bf2b10eaccb27c5a3e66a1212bef676f5bee6ef33ebb"}, + {file = "SQLAlchemy-2.0.37-cp37-cp37m-win_amd64.whl", hash = "sha256:8e47f1af09444f87c67b4f1bb6231e12ba6d4d9f03050d7fc88df6d075231a49"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6b788f14c5bb91db7f468dcf76f8b64423660a05e57fe277d3f4fad7b9dcb7ce"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521ef85c04c33009166777c77e76c8a676e2d8528dc83a57836b63ca9c69dcd1"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75311559f5c9881a9808eadbeb20ed8d8ba3f7225bef3afed2000c2a9f4d49b9"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cce918ada64c956b62ca2c2af59b125767097ec1dca89650a6221e887521bfd7"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9d087663b7e1feabea8c578d6887d59bb00388158e8bff3a76be11aa3f748ca2"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cf95a60b36997dad99692314c4713f141b61c5b0b4cc5c3426faad570b31ca01"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-win32.whl", hash = "sha256:d75ead7dd4d255068ea0f21492ee67937bd7c90964c8f3c2bea83c7b7f81b95f"}, + {file = "SQLAlchemy-2.0.37-cp38-cp38-win_amd64.whl", hash = "sha256:74bbd1d0a9bacf34266a7907d43260c8d65d31d691bb2356f41b17c2dca5b1d0"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:648ec5acf95ad59255452ef759054f2176849662af4521db6cb245263ae4aa33"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:35bd2df269de082065d4b23ae08502a47255832cc3f17619a5cea92ce478b02b"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f581d365af9373a738c49e0c51e8b18e08d8a6b1b15cc556773bcd8a192fa8b"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82df02816c14f8dc9f4d74aea4cb84a92f4b0620235daa76dde002409a3fbb5a"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94b564e38b344d3e67d2e224f0aec6ba09a77e4582ced41e7bfd0f757d926ec9"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:955a2a765aa1bd81aafa69ffda179d4fe3e2a3ad462a736ae5b6f387f78bfeb8"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-win32.whl", hash = "sha256:03f0528c53ca0b67094c4764523c1451ea15959bbf0a8a8a3096900014db0278"}, + {file = "SQLAlchemy-2.0.37-cp39-cp39-win_amd64.whl", hash = "sha256:4b12885dc85a2ab2b7d00995bac6d967bffa8594123b02ed21e8eb2205a7584b"}, + {file = "SQLAlchemy-2.0.37-py3-none-any.whl", hash = "sha256:a8998bf9f8658bd3839cbc44ddbe982955641863da0c1efe5b00c1ab4f5c16b1"}, + {file = "sqlalchemy-2.0.37.tar.gz", hash = "sha256:12b28d99a9c14eaf4055810df1001557176716de0167b91026e648e65229bffb"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] From e50299e7ce52ae1436a2bbf025976003fc8acfc3 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 11 Jan 2025 11:19:37 -0600 Subject: [PATCH 03/45] chore(l10n): New Crowdin updates (#4877) --- frontend/lang/messages/et-EE.json | 114 +++++++++++++++--------------- frontend/lang/messages/pl-PL.json | 2 +- frontend/lang/messages/ro-RO.json | 4 +- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/frontend/lang/messages/et-EE.json b/frontend/lang/messages/et-EE.json index 5c145c3ec..ea63b0643 100644 --- a/frontend/lang/messages/et-EE.json +++ b/frontend/lang/messages/et-EE.json @@ -972,65 +972,65 @@ "new-password": "Uus salasõna", "new-user": "Uus kasutaja", "password-has-been-reset-to-the-default-password": "Salasõna on lähtestatud selle vaikeväärtusega.", - "password-must-match": "Password must match", - "password-reset-failed": "Password reset failed", - "password-updated": "Password updated", - "password": "Password", - "password-strength": "Password is {strength}", - "please-enter-password": "Please enter your new password.", - "register": "Register", - "reset-password": "Reset Password", - "sign-in": "Sign in", - "total-mealplans": "Total MealPlans", - "total-users": "Total Users", - "upload-photo": "Upload Photo", - "use-8-characters-or-more-for-your-password": "Use 8 characters or more for your password", - "user-created": "User created", - "user-creation-failed": "User creation failed", - "user-deleted": "User deleted", - "user-id-with-value": "User ID: {id}", - "user-id": "User ID", - "user-password": "User Password", - "user-successfully-logged-in": "User Successfully Logged In", - "user-update-failed": "User update failed", - "user-updated": "User updated", - "user": "User", - "username": "Username", - "users-header": "USERS", - "users": "Users", - "user-not-found": "User not found", - "webhook-time": "Webhook Time", - "webhooks-enabled": "Webhooks Enabled", - "you-are-not-allowed-to-create-a-user": "You are not allowed to create a user", - "you-are-not-allowed-to-delete-this-user": "You are not allowed to delete this user", - "enable-advanced-content": "Enable Advanced Content", - "enable-advanced-content-description": "Enables advanced features like Recipe Scaling, API keys, Webhooks, and Data Management. Don't worry, you can always change this later", - "favorite-recipes": "Favorite Recipes", - "email-or-username": "Email or Username", - "remember-me": "Remember Me", - "please-enter-your-email-and-password": "Please enter your email and password", - "invalid-credentials": "Invalid Credentials", - "account-locked-please-try-again-later": "Account Locked. Please try again later", - "user-favorites": "User Favorites", + "password-must-match": "Salasõnad peavad kattuma", + "password-reset-failed": "Salasõna lähtestamine ebaõnnestus", + "password-updated": "Salasõna uuendatud", + "password": "Salasõna", + "password-strength": "Salasõna on {strength}", + "please-enter-password": "Palun sisesta oma uus salasõna.", + "register": "Registreeri", + "reset-password": "Lähtesta salasõna", + "sign-in": "Logi sisse", + "total-mealplans": "Kõik toitumisplaanid", + "total-users": "Kõik kasutajad", + "upload-photo": "Lae pilt üles", + "use-8-characters-or-more-for-your-password": "Kasutage oma salasõna jaoks vähemalt 8 tähemärki.", + "user-created": "Kasutaja loodud", + "user-creation-failed": "Kasutaja loomine ebaõnnestus", + "user-deleted": "Kasutaja kustutatud", + "user-id-with-value": "Kasutaja ID: {id}", + "user-id": "Kasutaja ID", + "user-password": "Kasutaja salasõna", + "user-successfully-logged-in": "Kasutaja edukalt sisse logitud", + "user-update-failed": "Kasutaja uuendamine ebaõnnestus", + "user-updated": "Kasutaja uuendatud", + "user": "Kasutaja", + "username": "Kasutajanimi", + "users-header": "KASUTAJAD", + "users": "Kasutajad", + "user-not-found": "Kasutajaid ei leitud", + "webhook-time": "Webhooki nimi", + "webhooks-enabled": "Webhookid lubatud", + "you-are-not-allowed-to-create-a-user": "Sul ei ole õigust luua uut kasutajat", + "you-are-not-allowed-to-delete-this-user": "Sul ei ole õigust kustutada seda kasutajat", + "enable-advanced-content": "Lubage täpsem sisu", + "enable-advanced-content-description": "Võimaldab täiustatud funktsioone, nagu retseptide skaleerimine, API võtmed, veebihaagid ja andmehaldus. Ärge muretsege, saate seda alati hiljem muuta.", + "favorite-recipes": "Lemmikretseptid", + "email-or-username": "Email või kasutajanimi", + "remember-me": "Mäleta mind", + "please-enter-your-email-and-password": "Palun sisesta oma email ja salasõna", + "invalid-credentials": "Valed kasutajaandmed", + "account-locked-please-try-again-later": "Kasutaja lukustatud. Palun proovi hiljem uuesti", + "user-favorites": "Kasutaja lemmikud", "password-strength-values": { - "weak": "Weak", - "good": "Good", - "strong": "Strong", - "very-strong": "Very Strong" + "weak": "Nõrk", + "good": "Hea", + "strong": "Tugev", + "very-strong": "Väga tugev" }, - "user-management": "User Management", - "reset-locked-users": "Reset Locked Users", - "admin-user-creation": "Admin User Creation", - "admin-user-management": "Admin User Management", - "user-details": "User Details", - "user-name": "User Name", - "authentication-method": "Authentication Method", - "authentication-method-hint": "This specifies how a user will authenticate with Mealie. If you're not sure, choose 'Mealie'", - "permissions": "Permissions", - "administrator": "Administrator", - "user-can-invite-other-to-group": "User can invite others to group", - "user-can-manage-group": "User can manage group", - "user-can-manage-household": "User can manage household", + "user-management": "Kasutajate haldamine", + "reset-locked-users": "Lähtesta lukustatud kasutajad", + "admin-user-creation": "Administraatori kasutaja loomine", + "admin-user-management": "Administraator-kasutaja haldamine", + "user-details": "Kasutaja üksikasjad", + "user-name": "Kasutaja nimi", + "authentication-method": "Autentimise meetod", + "authentication-method-hint": "Sellega määratakse kuidas kasutaja autendib Mealiega. Kui sa pole kindel, siis vali \"Mealie\"", + "permissions": "Õigused", + "administrator": "Administraator", + "user-can-invite-other-to-group": "Kasutaja võib kutsuda teisi gruppi", + "user-can-manage-group": "Kasutaja võib hallata gruppi", + "user-can-manage-household": "Kasutaja võib hallata leibkonda", "user-can-organize-group-data": "User can organize group data", "enable-advanced-features": "Enable advanced features", "it-looks-like-this-is-your-first-time-logging-in": "It looks like this is your first time logging in.", diff --git a/frontend/lang/messages/pl-PL.json b/frontend/lang/messages/pl-PL.json index 6b75b9d4f..313fd9626 100644 --- a/frontend/lang/messages/pl-PL.json +++ b/frontend/lang/messages/pl-PL.json @@ -518,7 +518,7 @@ "save-recipe-before-use": "Zapisz przepis przed użyciem", "section-title": "Tytuł rozdziału", "servings": "Porcje", - "serves-amount": "{amount} porcji", + "serves-amount": "Porcje {amount}", "share-recipe-message": "Chcę podzielić się z Tobą moim przepisem na {0}.", "show-nutrition-values": "Pokaż wartości odżywcze", "sodium-content": "Sód", diff --git a/frontend/lang/messages/ro-RO.json b/frontend/lang/messages/ro-RO.json index c1120e0f0..6aa00aee8 100644 --- a/frontend/lang/messages/ro-RO.json +++ b/frontend/lang/messages/ro-RO.json @@ -4,7 +4,7 @@ "about-mealie": "Despre Mealie", "api-docs": "Documentație API", "api-port": "API Port", - "application-mode": "Application Mode", + "application-mode": "Mod Aplicație", "database-type": "Tipul bazei de date", "database-url": "URL bază de date", "default-group": "Grup implicit", @@ -890,7 +890,7 @@ "all-recipes": "Toate reţetele", "backups": "Copii de rezervă", "categories": "Categorii", - "cookbooks": "Cărți de rețete", + "cookbooks": "Cărţi de bucate", "dashboard": "Panou de control", "home-page": "Pagina principală", "manage-users": "Gestionare utilizatori", From dde93e78c947e054f0f382156e42fb28089c66db Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sun, 12 Jan 2025 10:49:18 -0600 Subject: [PATCH 04/45] chore(l10n): New Crowdin updates (#4882) --- frontend/lang/messages/ar-SA.json | 274 +++++++++--------- mealie/lang/messages/ar-SA.json | 70 ++--- .../seed/resources/labels/locales/ar-SA.json | 12 +- .../seed/resources/units/locales/ar-SA.json | 62 ++-- 4 files changed, 209 insertions(+), 209 deletions(-) diff --git a/frontend/lang/messages/ar-SA.json b/frontend/lang/messages/ar-SA.json index f8e5b6aaa..8e3a53c57 100644 --- a/frontend/lang/messages/ar-SA.json +++ b/frontend/lang/messages/ar-SA.json @@ -250,60 +250,60 @@ "invite": "دعوة", "looking-to-update-your-profile": "هل ترغب في تحديث ملفك الشخصي؟", "default-recipe-preferences-description": "هذه هي الإعدادات الافتراضية عند إنشاء وصفة جديدة في مجموعتك. يمكن تغيير هذه الوصفات الفردية في قائمة إعدادات الوصفات.", - "default-recipe-preferences": "Default Recipe Preferences", + "default-recipe-preferences": "تفضيلات الوصفة الافتراضية", "group-preferences": "إعدادات المجموعة", "private-group": "مجموعة خاصة", - "private-group-description": "Setting your group to private will disable all public view options. This overrides any individual public view settings", - "enable-public-access": "Enable Public Access", - "enable-public-access-description": "Make group recipes public by default, and allow visitors to view recipes without logging-in", + "private-group-description": "سيؤدي تعيين مجموعتك إلى الخاص إلى تعطيل جميع خيارات العرض العام. وهذا يلغي أي إعدادات عرض عام فردية", + "enable-public-access": "تمكين الوصول للعموم", + "enable-public-access-description": "جعل وصفات المجموعة عامة بشكل افتراضي، والسماح للزوار بعرض الوصفات دون تسجيل الدخول", "allow-users-outside-of-your-group-to-see-your-recipes": "السماح للمستخدمين خارج مجموعتك لمشاهدة وصفاتك", - "allow-users-outside-of-your-group-to-see-your-recipes-description": "When enabled you can use a public share link to share specific recipes without authorizing the user. When disabled, you can only share recipes with users who are in your group or with a pre-generated private link", + "allow-users-outside-of-your-group-to-see-your-recipes-description": "عند التمكين يمكنك استخدام رابط المشاركة العامة لمشاركة وصفات محددة دون تفويض المستخدم. عند التعطيل، يمكنك مشاركة الوصفات فقط مع المستخدمين الموجودين في مجموعتك أو مع رابط خاص تم إنشاؤه مسبقاً", "show-nutrition-information": "عرض معلومات التغذية", - "show-nutrition-information-description": "When enabled the nutrition information will be shown on the recipe if available. If there is no nutrition information available, the nutrition information will not be shown", - "show-recipe-assets": "Show recipe assets", - "show-recipe-assets-description": "When enabled the recipe assets will be shown on the recipe if available", - "default-to-landscape-view": "Default to landscape view", - "default-to-landscape-view-description": "When enabled the recipe header section will be shown in landscape view", + "show-nutrition-information-description": "عندما يتم تمكين المعلومات الغذائية ستظهر على الوصفة إذا كانت متاحة. وفي حالة عدم توافر معلومات عن التغذية، لن تظهر المعلومات المتعلقة بالتغذية", + "show-recipe-assets": "إظهار أصول الوصفة", + "show-recipe-assets-description": "عند تمكين الوصفة، سيتم عرض أصول الوصفة على الوصفة إذا كانت متوفرة", + "default-to-landscape-view": "الافتراضي للعرض الأفقي", + "default-to-landscape-view-description": "عند تمكين قسم رأس الوصفة سوف يظهر في العرض الأفقي", "disable-users-from-commenting-on-recipes": "إيقاف المستخدمين من التعليق على الوصفات", - "disable-users-from-commenting-on-recipes-description": "Hides the comment section on the recipe page and disables commenting", - "disable-organizing-recipe-ingredients-by-units-and-food": "Disable organizing recipe ingredients by units and food", - "disable-organizing-recipe-ingredients-by-units-and-food-description": "Hides the Food, Unit, and Amount fields for ingredients and treats ingredients as plain text fields", - "general-preferences": "General Preferences", - "group-recipe-preferences": "Group Recipe Preferences", + "disable-users-from-commenting-on-recipes-description": "يخفي قسم التعليق على صفحة الوصفة ويعطل التعليق", + "disable-organizing-recipe-ingredients-by-units-and-food": "تعطيل تنظيم عناصر الوصفة حسب الوحدات والطعام", + "disable-organizing-recipe-ingredients-by-units-and-food-description": "يخفي حقول الطعام والوحدة والكمية للمكونات ويعامل المكونات كحقول نصية عادية", + "general-preferences": "الإعدادات العامة", + "group-recipe-preferences": "تفضيلات الوصفة للمجموعة", "report": "تقرير", - "report-with-id": "Report ID: {id}", - "group-management": "Group Management", - "admin-group-management": "Admin Group Management", - "admin-group-management-text": "Changes to this group will be reflected immediately.", - "group-id-value": "Group Id: {0}", - "total-households": "Total Households", - "you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household" + "report-with-id": "معرف التقرير: {id}", + "group-management": "إدارة المجموعة", + "admin-group-management": "إدارة مجموعة المشرف", + "admin-group-management-text": "التغييرات التي ستطرأ على هذه المجموعة ستنعكس على الفور.", + "group-id-value": "معرف المجموعة: {0}", + "total-households": "مجموع المنزل", + "you-must-select-a-group-before-selecting-a-household": "يجب عليك تحديد مجموعة قبل تحديد المنزل" }, "household": { - "household": "Household", - "households": "Households", - "user-household": "User Household", - "create-household": "Create Household", - "household-name": "Household Name", - "household-group": "Household Group", - "household-management": "Household Management", - "manage-households": "Manage Households", - "admin-household-management": "Admin Household Management", - "admin-household-management-text": "Changes to this household will be reflected immediately.", - "household-id-value": "Household Id: {0}", - "private-household": "Private Household", - "private-household-description": "Setting your household to private will disable all public view options. This overrides any individual public view settings", - "lock-recipe-edits-from-other-households": "Lock recipe edits from other households", - "lock-recipe-edits-from-other-households-description": "When enabled only users in your household can edit recipes created by your household", - "household-recipe-preferences": "Household Recipe Preferences", - "default-recipe-preferences-description": "These are the default settings when a new recipe is created in your household. These can be changed for individual recipes in the recipe settings menu.", - "allow-users-outside-of-your-household-to-see-your-recipes": "Allow users outside of your household to see your recipes", - "allow-users-outside-of-your-household-to-see-your-recipes-description": "When enabled you can use a public share link to share specific recipes without authorizing the user. When disabled, you can only share recipes with users who are in your household or with a pre-generated private link", - "household-preferences": "Household Preferences" + "household": "المنزل", + "households": "المنازل", + "user-household": "منزل المستخدم", + "create-household": "إنشاء منزل", + "household-name": "اسم المنزل", + "household-group": "مجموعة المنزل", + "household-management": "إدارة المنزل", + "manage-households": "إدارة المنازل", + "admin-household-management": "إدارة مشرف المنزل", + "admin-household-management-text": "التغييرات التي ستطرأ على هذا المنزل ستنعكس على الفور.", + "household-id-value": "معرف المنزل: {0}", + "private-household": "منزل خاص", + "private-household-description": "سيؤدي تعيين المنزل إلى خاص إلى تعطيل جميع خيارات العرض العام. وهذا يلغي أي إعدادات عرض عام فردية", + "lock-recipe-edits-from-other-households": "إقفال تحرير الوصفة من المنازل الأخرى", + "lock-recipe-edits-from-other-households-description": "عند التمكين, المستخدمين فقط في أسرتك المعيشية يمكنهم تعديل الوصفات التي أنشأتها أسرتك", + "household-recipe-preferences": "تفضيلات الوصفة المنزلية", + "default-recipe-preferences-description": "هذه هي الإعدادات الافتراضية عند إنشاء وصفة جديدة في منزلك. يمكن تغيير الوصفات الفردية في قائمة إعدادات الوصفة.", + "allow-users-outside-of-your-household-to-see-your-recipes": "السماح للمستخدمين خارج منزلك بمشاهدة وصفاتك", + "allow-users-outside-of-your-household-to-see-your-recipes-description": "عند التمكين يمكنك استخدام رابط المشاركة العامة لمشاركة وصفات محددة دون تفويض المستخدم. عند التعطيل، يمكنك مشاركة الوصفات فقط مع المستخدمين الموجودين في منزلك أو مع رابط خاص تم إنشاؤه مسبقاً", + "household-preferences": "تفضيلات المنزل" }, "meal-plan": { "create-a-new-meal-plan": "إنشاء خطة وجبة جديدة", - "update-this-meal-plan": "Update this Meal Plan", + "update-this-meal-plan": "تحديث خِطَّة الوجبة الغذائية هذه", "dinner-this-week": "العشاء لهذا الأسبوع", "dinner-today": "العشاء اليوم", "dinner-tonight": "العشاء الليلة", @@ -321,95 +321,95 @@ "mealplan-settings": "اعدادات خطة الوجبات", "mealplan-update-failed": "فشل تحديث خطة الوجبات", "mealplan-updated": "تم تحديث خطة الوجبات", - "mealplan-households-description": "If no household is selected, recipes can be added from any household", - "any-category": "Any Category", - "any-tag": "Any Tag", - "any-household": "Any Household", + "mealplan-households-description": "إذا لم يتم اختيار منزل، يمكن إضافة وصفات من أي منزل", + "any-category": "أي فئة", + "any-tag": "أي وسم", + "any-household": "أي منزل", "no-meal-plan-defined-yet": "لم يتم تحديد خطة بعد", "no-meal-planned-for-today": "لم يتم تخطيط وجبة لهذا اليوم", - "numberOfDays-hint": "Number of days on page load", - "numberOfDays-label": "Default Days", + "numberOfDays-hint": "عدد الأيام عند تحميل الصفحة", + "numberOfDays-label": "الأيام الافتراضية", "only-recipes-with-these-categories-will-be-used-in-meal-plans": "فقط الوجبات التي تحتوي على التصنيفات التالية سوف تستخدم لإنشاء خطتك", "planner": "المخطط", - "quick-week": "Quick Week", + "quick-week": "أسبوع سريع", "side": "وجبة جانبية", "sides": "الوجبات الجانبية", "start-date": "تاريخ البدء", - "rule-day": "Rule Day", + "rule-day": "يوم القاعدة", "meal-type": "نوع الوجبة", "breakfast": "الإفطار", "lunch": "الغداء", "dinner": "العشاء", "type-any": "أي", "day-any": "أي", - "editor": "Editor", + "editor": "المحرر", "meal-recipe": "وصفة الوجبة", "meal-title": "عنوان الوجبة", "meal-note": "ملاحظة الوجبة", "note-only": "ملاحظة فقط", "random-meal": "وجبة عشوائية", "random-dinner": "عشاء عشوائي", - "random-side": "Random Side", - "this-rule-will-apply": "This rule will apply {dayCriteria} {mealTypeCriteria}.", + "random-side": "جانب عشوائي", + "this-rule-will-apply": "هذه القاعدة سوف تطبق على {dayCriteria} {mealTypeCriteria}.", "to-all-days": "إلى جميع الأيام", - "on-days": "on {0}s", + "on-days": "على أيام {0}", "for-all-meal-types": "لجميع أنواع الوجبات", - "for-type-meal-types": "for {0} meal types", - "meal-plan-rules": "Meal Plan Rules", + "for-type-meal-types": "لأنواع الوجبات {0}", + "meal-plan-rules": "قواعد خِطَّة وجبة الطعام", "new-rule": "قاعدة جديدة", - "meal-plan-rules-description": "You can create rules for auto selecting recipes for your meal plans. These rules are used by the server to determine the random pool of recipes to select from when creating meal plans. Note that if rules have the same day/type constraints then the rule filters will be merged. In practice, it's unnecessary to create duplicate rules, but it's possible to do so.", - "new-rule-description": "When creating a new rule for a meal plan you can restrict the rule to be applicable for a specific day of the week and/or a specific type of meal. To apply a rule to all days or all meal types you can set the rule to \"Any\" which will apply it to all the possible values for the day and/or meal type.", + "meal-plan-rules-description": "يمكنك إنشاء قواعد لاختيار الوصفات التلقائية لخطط وجبتك الغذائية. وتستخدم هذه القواعد من قبل الخادم لتحديد مجموعة عشوائية من الوصفات التي يتم اختيارها من خلال إنشاء خطط الوجبات. لاحظ أنه إذا كانت القواعد تحتوي على نفس قيود اليوم/النوع فسيتم دمج عوامل تصفية القاعدة. من الناحية العملية، ليس من الضروري إنشاء قواعد مكررة، ولكن من الممكن فعل ذلك.", + "new-rule-description": "عند إنشاء قاعدة جديدة لخطة وجبة غذائية، يمكنك تقييد القاعدة لتكون قابلة للتطبيق ليوم محدد من الأسبوع و/أو نوع محدد من الوجبات. لتطبيق قاعدة على جميع الأيام أو جميع أنواع الوجبات الغذائية يمكنك تعيين القاعدة إلى \"أي كان\" التي ستطبقها على جميع القيم الممكنة لليوم و/أو نوع الوجبة.", "recipe-rules": "قواعد الوصفات", "applies-to-all-days": "ينطبق على جميع الأيام", - "applies-on-days": "Applies on {0}s", - "meal-plan-settings": "Meal Plan Settings" + "applies-on-days": "يطبق على أيام {0}", + "meal-plan-settings": "إعدادات خِطَّة الوجبات الغذائية" }, "migration": { - "migration-data-removed": "Migration data removed", - "new-migration": "New Migration", + "migration-data-removed": "حذف بيانات الهجرة", + "new-migration": "هجرة جديدة", "no-file-selected": "لم يتمّ اختيار أيّ ملفّ", - "no-migration-data-available": "No Migration Data Available", - "previous-migrations": "Previous Migrations", + "no-migration-data-available": "لا توجد بيانات هجرة متوفرة", + "previous-migrations": "الهجرة السابقة", "recipe-migration": "نقل الوصفة", "chowdown": { - "description": "Migrate data from Chowdown", - "description-long": "Mealie natively supports the chowdown repository format. Download the code repository as a .zip file and upload it below.", - "title": "Chowdown" + "description": "نقل البيانات من \"Chowdown\"", + "description-long": "ميلي يدعم بشكل محلي تنسيق مستودع طعام. يجب تنزيل مستودع التعليمات البرمجية CODE REPOSITORY كملف مضغوط ZIP وتحميله أدناه.", + "title": "\"Chowdown\"" }, "nextcloud": { - "description": "Migrate data from a Nextcloud Cookbook instance", - "description-long": "Nextcloud recipes can be imported from a zip file that contains the data stored in Nextcloud. See the example folder structure below to ensure your recipes are able to be imported.", - "title": "Nextcloud Cookbook" + "description": "نقل البيانات من نموذج كتاب طبخ NEXTCLOUD", + "description-long": "يمكن استيراد الوصفات السحابية من مِلَفّ مضغوط ZIP يحتوي على البيانات المخزنة في Nextcloud. راجع بنية مجلد المثال أدناه للتأكد من أن وصفاتك قابلة للاستيراد.", + "title": "كتاب طبخ " }, "copymethat": { - "description-long": "Mealie can import recipes from Copy Me That. Export your recipes in HTML format, then upload the .zip below.", - "title": "Copy Me That Recipe Manager" + "description-long": "يمكن لميلي استيراد الوصفات من نسخ لي. يجب تصدير وصفاتك بتنسيق HTML، ثم تحميل ZIP أدناه.", + "title": "انسخ لي مدير الوصفة" }, "paprika": { - "description-long": "Mealie can import recipes from the Paprika application. Export your recipes from paprika, rename the export extension to .zip and upload it below.", - "title": "Paprika Recipe Manager" + "description-long": "يمكن لميلي استيراد الوصفات من تطبيق PAPRIKA. يجب تصدير وصفاتك من PAPRIKA، وإعادة تسمية امتداد التصدير إلى .ZIP وتحميله أدناه.", + "title": "مدير وصفة بابريكا" }, "mealie-pre-v1": { "description-long": "Mealie can import recipes from the Mealie application from a pre v1.0 release. Export your recipes from your old instance, and upload the zip file below. Note that only recipes can be imported from the export.", - "title": "Mealie Pre v1.0" + "title": "ميلي إصدار قبل 1.0" }, "tandoor": { "description-long": "Mealie can import recipes from Tandoor. Export your data in the \"Default\" format, then upload the .zip below.", - "title": "Tandoor Recipes" + "title": "وصفات تاندور" }, - "recipe-data-migrations": "Recipe Data Migrations", + "recipe-data-migrations": "وصفة 2", "recipe-data-migrations-explanation": "Recipes can be migrated from another supported application to Mealie. This is a great way to get started with Mealie.", "coming-from-another-application-or-an-even-older-version-of-mealie": "Coming from another application or an even older version of Mealie? Check out migrations and see if your data can be imported.", - "choose-migration-type": "Choose Migration Type", - "tag-all-recipes": "Tag all recipes with {tag-name} tag", + "choose-migration-type": "اختر نوع الترحيل", + "tag-all-recipes": "وسم جميع الوصفات باستخدام علامة {tag-name}", "nextcloud-text": "Nextcloud recipes can be imported from a zip file that contains the data stored in Nextcloud. See the example folder structure below to ensure your recipes are able to be imported.", "chowdown-text": "Mealie natively supports the chowdown repository format. Download the code repository as a .zip file and upload it below.", - "recipe-1": "Recipe 1", - "recipe-2": "Recipe 2", + "recipe-1": "وصفة 1", + "recipe-2": "وصفة 2", "paprika-text": "Mealie can import recipes from the Paprika application. Export your recipes from paprika, rename the export extension to .zip and upload it below.", "mealie-text": "Mealie can import recipes from the Mealie application from a pre v1.0 release. Export your recipes from your old instance, and upload the zip file below. Note that only recipes can be imported from the export.", "plantoeat": { - "title": "Plan to Eat", + "title": "خِطَّة تناول الطعام", "description-long": "Mealie can import recipies from Plan to Eat." }, "myrecipebox": { @@ -417,44 +417,44 @@ "description-long": "Mealie can import recipes from My Recipe Box. Export your recipes in CSV format, then upload the .csv file below." }, "recipekeeper": { - "title": "Recipe Keeper", + "title": "مدير الوصفة", "description-long": "Mealie can import recipes from Recipe Keeper. Export your recipes in zip format, then upload the .zip file below." } }, "new-recipe": { - "bulk-add": "Bulk Add", + "bulk-add": "إضافة مجموعة", "error-details": "Only websites containing ld+json or microdata can be imported by Mealie. Most major recipe websites support this data structure. If your site cannot be imported but there is json data in the log, please submit a github issue with the URL and data.", "error-title": "Looks Like We Couldn't Find Anything", - "from-url": "Import a Recipe", + "from-url": "استيراد وصفة", "github-issues": "مشاكل GitHub", "google-ld-json-info": "معرف Google + معلومات json", "must-be-a-valid-url": "يجب أن يكون عنوان URL صالحًا", "paste-in-your-recipe-data-each-line-will-be-treated-as-an-item-in-a-list": "Paste in your recipe data. Each line will be treated as an item in a list", "recipe-markup-specification": "Recipe Markup Specification", - "recipe-url": "Recipe URL", - "recipe-html-or-json": "Recipe HTML or JSON", - "upload-a-recipe": "Upload a Recipe", - "upload-individual-zip-file": "Upload an individual .zip file exported from another Mealie instance.", - "url-form-hint": "Copy and paste a link from your favorite recipe website", - "view-scraped-data": "View Scraped Data", - "trim-whitespace-description": "Trim leading and trailing whitespace as well as blank lines", - "trim-prefix-description": "Trim first character from each line", + "recipe-url": "رابط الوصفة", + "recipe-html-or-json": "وصفة HTML أو JSON", + "upload-a-recipe": "تحميل وصفة", + "upload-individual-zip-file": "تحميل مِلَفّ zip فردي تم تصديره من مثيل Malie آخر.", + "url-form-hint": "نسخ ولصق رابط من موقعك المفضل للوصفة", + "view-scraped-data": "عرض البيانات المكشوفة", + "trim-whitespace-description": "قص المسافات البيضاء البادئة واللاحقة وكذلك الأسطر الفارغة", + "trim-prefix-description": "قص الحرف الأول من كل سطر", "split-by-numbered-line-description": "Attempts to split a paragraph by matching '1)' or '1.' patterns", - "import-by-url": "Import a recipe by URL", - "create-manually": "Create a recipe manually", - "make-recipe-image": "Make this the recipe image" + "import-by-url": "استيراد وصفة عن طريق عنوان URL", + "create-manually": "إنشاء وصفة يدوياً", + "make-recipe-image": "اجعل هذه صورة الوصفة" }, "page": { - "404-page-not-found": "404 Page not found", - "all-recipes": "All Recipes", - "new-page-created": "New page created", + "404-page-not-found": "404: لم يتم العثور على الصفحة", + "all-recipes": "جميع الوصفات", + "new-page-created": "تم إنشاء الصفحة الجديدة", "page": "الصفحة", - "page-creation-failed": "Page creation failed", + "page-creation-failed": "فشل إنشاء الصفحة", "page-deleted": "تم حذف الصفحة", "page-deletion-failed": "حذف الصفحة فشل", "page-update-failed": "تحديث الصفحة فشل", "page-updated": "تم تحديث صفحة", - "pages-update-failed": "Pages update failed", + "pages-update-failed": "فشل تحديث الصفحات", "pages-updated": "Pages updated", "404-not-found": "لم يتم العثور على الصفحة. خطأ 404", "an-error-occurred": "حصل خطأ ما" @@ -500,42 +500,42 @@ "object-value": "Object Value", "original-url": "Original URL", "perform-time": "Cook Time", - "prep-time": "Prep Time", - "protein-content": "Protein", - "public-recipe": "Public Recipe", - "recipe-created": "Recipe created", - "recipe-creation-failed": "Recipe creation failed", - "recipe-deleted": "Recipe deleted", - "recipe-image": "Recipe Image", - "recipe-image-updated": "Recipe image updated", - "recipe-name": "Recipe Name", - "recipe-settings": "Recipe Settings", - "recipe-update-failed": "Recipe update failed", - "recipe-updated": "Recipe updated", - "remove-from-favorites": "Remove from Favorites", - "remove-section": "Remove Section", - "saturated-fat-content": "Saturated fat", - "save-recipe-before-use": "Save recipe before use", - "section-title": "Section Title", - "servings": "Servings", - "serves-amount": "Serves {amount}", - "share-recipe-message": "I wanted to share my {0} recipe with you.", + "prep-time": "وقت التحضير", + "protein-content": "البروتين", + "public-recipe": "وصفة عامة", + "recipe-created": "تم إنشاء الوصفة", + "recipe-creation-failed": "فشل إنشاء الوصفة", + "recipe-deleted": "تم حذف الوصفة", + "recipe-image": "صورة الوصفة", + "recipe-image-updated": "تم تحديث صورة الوصفة", + "recipe-name": "اسم الوصفة", + "recipe-settings": "إعدادات الوصفة", + "recipe-update-failed": "فشل تحديث الوصفة", + "recipe-updated": "تم تحديث الوصفة", + "remove-from-favorites": "إزالة من المفضلات", + "remove-section": "إزالة القسم", + "saturated-fat-content": "الدهون المشبعة", + "save-recipe-before-use": "حفظ الوصفة قبل الاستخدام", + "section-title": "عنوان القسم", + "servings": "حصص الطعام", + "serves-amount": "{amount} حصص", + "share-recipe-message": "أردت أن أشارككم وصفة {0} الخاصة بي.", "show-nutrition-values": "Show Nutrition Values", - "sodium-content": "Sodium", - "step-index": "Step: {step}", - "sugar-content": "Sugar", - "title": "Title", - "total-time": "Total Time", - "trans-fat-content": "Trans-fat", - "unable-to-delete-recipe": "Unable to Delete Recipe", - "unsaturated-fat-content": "Unsaturated fat", - "no-recipe": "No Recipe", - "locked-by-owner": "Locked by Owner", - "join-the-conversation": "Join the Conversation", - "add-recipe-to-mealplan": "Add Recipe to Mealplan", - "entry-type": "Entry Type", - "date-format-hint": "MM/DD/YYYY format", - "date-format-hint-yyyy-mm-dd": "YYYY-MM-DD format", + "sodium-content": "صوديوم", + "step-index": "الخطوة: {step}", + "sugar-content": "سكر", + "title": "العنوان", + "total-time": "الوقت الإجمالي", + "trans-fat-content": "الدهون المتحولة", + "unable-to-delete-recipe": "تعذر حذف الوصفة", + "unsaturated-fat-content": "دهون غير مشبعة", + "no-recipe": "لا يوجد وصفة", + "locked-by-owner": "مقفلة من قبل المالك", + "join-the-conversation": "انضم للمحادثة", + "add-recipe-to-mealplan": "إضافة الوصفة إلى خِطَّة الوجبة", + "entry-type": "نوع الإدخال", + "date-format-hint": "صيغة MM/DD/YYYYY", + "date-format-hint-yyyy-mm-dd": "صيغة YYY-MM-DD", "add-to-list": "Add to List", "add-to-plan": "Add to Plan", "add-to-timeline": "Add to Timeline", diff --git a/mealie/lang/messages/ar-SA.json b/mealie/lang/messages/ar-SA.json index 590474cab..dd6c0fc42 100644 --- a/mealie/lang/messages/ar-SA.json +++ b/mealie/lang/messages/ar-SA.json @@ -4,18 +4,18 @@ }, "recipe": { "unique-name-error": "يجب أن تكون أسماء الوصفات فريدة", - "recipe-created": "Recipe Created", + "recipe-created": "تم إنشاء الوصفة", "recipe-defaults": { - "ingredient-note": "1 Cup Flour", - "step-text": "Recipe steps as well as other fields in the recipe page support markdown syntax.\n\n**Add a link**\n\n[My Link](https://demo.mealie.io)\n" + "ingredient-note": "كوب 1 طحين", + "step-text": "تدعم خطوات الوصفة بالإضافة إلى الحقول الأخرى في صفحة الوصفة صياغة تخفيض السعر. **أضف رابطًا** [الرابط الخاص بي](https://demo.mealie.io)\n" }, "servings-text": { - "makes": "Makes", - "serves": "Serves", - "serving": "Serving", - "servings": "Servings", - "yield": "Yield", - "yields": "Yields" + "makes": "تصنع", + "serves": "يكفي ل", + "serving": "حصة الطعام", + "servings": "حصص الطعام", + "yield": "العائد", + "yields": "العائد" } }, "mealplan": { @@ -28,53 +28,53 @@ "ldap-update-password-unavailable": "غير قادر على تحديث كلمة المرور، المستخدم يتم التحكم به بواسطة LDAP" }, "group": { - "report-deleted": "تم حذف التقرير" + "report-deleted": "تم حذف التقرير." }, "exceptions": { - "permission_denied": "لا يوجد لديك صلاحيات كافية لتفيذ هذا الإجراء", + "permission_denied": "لا يوجد لديك صلاحيات كافية لتنفيذ هذا الإجراء", "no-entry-found": "لم يتم العثور على الصفحة المطلوبة", "integrity-error": "خطأ في سلامة قاعدة البيانات", - "username-conflict-error": "اسم المستخدم هذا مستخدم بالفعل", + "username-conflict-error": "اسم المستخدم هذا مستخدم مسبقاً", "email-conflict-error": "هذا البريد مستخدم مسبقاً" }, "notifications": { "generic-created": "تم إنشاء {name}", "generic-updated": "تم تحديث {name}", - "generic-created-with-url": "تم إنشاء {name} ، {url}", + "generic-created-with-url": "تم إنشاء {name}، {url}", "generic-updated-with-url": "{name} تم تحديثه، {url}", "generic-duplicated": "تم تكرار {name}", "generic-deleted": "تم حذف {name}" }, "datetime": { - "year": "year|years", - "day": "day|days", - "hour": "hour|hours", - "minute": "minute|minutes", - "second": "second|seconds", - "millisecond": "millisecond|milliseconds", - "microsecond": "microsecond|microseconds" + "year": "سنة|سنوات", + "day": "يوم|أيام", + "hour": "ساعة|ساعات", + "minute": "دقيقة|دقائق", + "second": "ثانية|ثواني", + "millisecond": "مللي ثانية|مللي ثانية", + "microsecond": "مكرو ثانية|مكرو ثانية" }, "emails": { "password": { - "subject": "Mealie Forgot Password", - "header_text": "Forgot Password", - "message_top": "You have requested to reset your password.", - "message_bottom": "Please click the button above to reset your password.", - "button_text": "Reset Password" + "subject": "نسيت كلمة المرور", + "header_text": "نسيت كلمة المرور", + "message_top": "لقد طلبت إعادة تعيين كلمة المرور الخاصة بك.", + "message_bottom": "الرجاء النقر على الزر أعلاه لإعادة تعيين كلمة المرور الخاصة بك.", + "button_text": "إعادة ضبط كلمة المرور" }, "invitation": { - "subject": "Invitation to join Mealie", - "header_text": "You're Invited!", - "message_top": "You have been invited to join Mealie.", - "message_bottom": "Please click the button above to accept the invitation.", - "button_text": "Accept Invitation" + "subject": "دعوة للانضمام إلى ميلي", + "header_text": "أنت مدعو!", + "message_top": "لقد تمت دعوتك للانضمام إلى ميلي.", + "message_bottom": "الرجاء النقر على الزر أعلاه لقبول الدعوة.", + "button_text": "قَبُول الدعوة" }, "test": { - "subject": "Mealie Test Email", - "header_text": "Test Email", - "message_top": "This is a test email.", - "message_bottom": "Please click the button above to test the email.", - "button_text": "Open Mealie" + "subject": "بريد إلكتروني لاختبار ميلي", + "header_text": "بريد إلكتروني تجريبي", + "message_top": "هذا بريد إلكتروني اختباري.", + "message_bottom": "الرجاء النقر على الزر أعلاه لاختبار البريد الإلكتروني.", + "button_text": "فتح ميلي" } } } diff --git a/mealie/repos/seed/resources/labels/locales/ar-SA.json b/mealie/repos/seed/resources/labels/locales/ar-SA.json index 994be3de0..6e362c5ab 100644 --- a/mealie/repos/seed/resources/labels/locales/ar-SA.json +++ b/mealie/repos/seed/resources/labels/locales/ar-SA.json @@ -1,12 +1,12 @@ [ { - "name": "Produce" + "name": "المنتج" }, { "name": "الحبوب" }, { - "name": "الفواكة" + "name": "آلفواكه" }, { "name": "الخضراوات" @@ -27,10 +27,10 @@ "name": "المعلبات" }, { - "name": "Condiments" + "name": "الباهرات" }, { - "name": "Confectionary" + "name": "الحَلْوَيَات" }, { "name": "منتجات الألبان" @@ -42,7 +42,7 @@ "name": "الأغذية الصحية" }, { - "name": "Household" + "name": "المنزل" }, { "name": "منتجات اللحوم" @@ -54,7 +54,7 @@ "name": "التوابل" }, { - "name": "الحلويات" + "name": "الحَلْوَيَات" }, { "name": "الكحول" diff --git a/mealie/repos/seed/resources/units/locales/ar-SA.json b/mealie/repos/seed/resources/units/locales/ar-SA.json index 68a197426..7d57ddd40 100644 --- a/mealie/repos/seed/resources/units/locales/ar-SA.json +++ b/mealie/repos/seed/resources/units/locales/ar-SA.json @@ -1,140 +1,140 @@ { "teaspoon": { "name": "ملعقة صغيرة", - "plural_name": "teaspoons", + "plural_name": "ملعقة صغيرة", "description": "", "abbreviation": "ملعقة صغيرة" }, "tablespoon": { "name": "ملعقة كبيرة", - "plural_name": "tablespoons", + "plural_name": "ملعقة كبيرة", "description": "", "abbreviation": "ملعقة كبيرة" }, "cup": { "name": "كوب", - "plural_name": "cups", + "plural_name": "كوب", "description": "", - "abbreviation": "c" + "abbreviation": "درجة مئوية" }, "fluid-ounce": { - "name": "أوقية 200gm", - "plural_name": "fluid ounces", + "name": "أونصة سائل", + "plural_name": "أونصة سائل", "description": "", - "abbreviation": "أوقية 200gm" + "abbreviation": "أونصة سائل" }, "pint": { "name": "نصف لتر", - "plural_name": "pints", + "plural_name": "نصف لتر", "description": "", "abbreviation": "نصف لتر" }, "quart": { "name": "الربع", - "plural_name": "quarts", + "plural_name": "لتر", "description": "", "abbreviation": "الربع" }, "gallon": { "name": "جالون", - "plural_name": "gallons", + "plural_name": "جالون", "description": "", "abbreviation": "جالون" }, "milliliter": { - "name": "ميليلتر", - "plural_name": "milliliters", + "name": "ميلي لتر", + "plural_name": "مللي لترات", "description": "", "abbreviation": "مل" }, "liter": { "name": "لتر", - "plural_name": "liters", + "plural_name": "لترات", "description": "", "abbreviation": "لتر" }, "pound": { "name": "رطل", - "plural_name": "pounds", + "plural_name": "رطل", "description": "", "abbreviation": "رطل", - "plural_abbreviation": "lbs" + "plural_abbreviation": "رطل" }, "ounce": { "name": "أوقية / ألأونضه", - "plural_name": "ounces", + "plural_name": "أوقية / ألأونضه", "description": "", "abbreviation": "أونصة" }, "gram": { "name": "جرام", - "plural_name": "grams", + "plural_name": "جرامات", "description": "", "abbreviation": "غرام" }, "kilogram": { "name": "كيلوغرام", - "plural_name": "kilograms", + "plural_name": "كيلوغرامات", "description": "", "abbreviation": "كيلوغرام" }, "milligram": { "name": "مليغرام", - "plural_name": "milligrams", + "plural_name": "ميليغرامات", "description": "", "abbreviation": "مليغرام" }, "splash": { "name": "دفقة", - "plural_name": "splashes", + "plural_name": "رشه", "description": "", "abbreviation": "" }, "dash": { "name": "اندفاع", - "plural_name": "dashes", + "plural_name": "رشه", "description": "", "abbreviation": "" }, "serving": { "name": "حصة الطعام", - "plural_name": "servings", + "plural_name": "حصة طعام", "description": "", "abbreviation": "" }, "head": { "name": "رأس", - "plural_name": "heads", + "plural_name": "رؤوس", "description": "", "abbreviation": "" }, "clove": { "name": "القرنفل", - "plural_name": "cloves", + "plural_name": "القرنفل", "description": "", "abbreviation": "" }, "can": { "name": "يمكن", - "plural_name": "cans", + "plural_name": "علب", "description": "", "abbreviation": "" }, "bunch": { - "name": "bunch", - "plural_name": "bunches", + "name": "باقة", + "plural_name": "باقات", "description": "", "abbreviation": "" }, "pack": { - "name": "pack", - "plural_name": "packs", + "name": "حُزْمَة", + "plural_name": "حزمات", "description": "", "abbreviation": "" }, "pinch": { - "name": "pinch", - "plural_name": "pinches", + "name": "رشه", + "plural_name": "رشاة", "description": "", "abbreviation": "" } From 2e13f33eb156facfee3483c9cf6a4f305c18b424 Mon Sep 17 00:00:00 2001 From: Chip Date: Mon, 13 Jan 2025 08:39:42 -0500 Subject: [PATCH 05/45] docs: Update FAQ to include Nutritional Values and enabling per recipe / household (#4887) Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- docs/docs/documentation/getting-started/faq.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/docs/documentation/getting-started/faq.md b/docs/docs/documentation/getting-started/faq.md index b07dc44ab..27f63136a 100644 --- a/docs/docs/documentation/getting-started/faq.md +++ b/docs/docs/documentation/getting-started/faq.md @@ -33,6 +33,24 @@ Do the following for each recipe you want to intelligently handle ingredients. Scaling up this recipe or adding it to a Shopping List will now smartly take care of ingredient amounts and duplicate combinations. +## How do I enable Nutrtional Values? +Mealie can store Nutritional Information for Recipes. Please note that the values you enter are static for the recipe and no scaling is being done when channging Servings / Yield. + +Do the following to enable Nutritional Values on individual Recipes, or to modify your Household Recipe Preferences + +### Show Nutritional Values on a Single Recipe +1. Go to a recipe +2. Click the Edit button/icon +3. Click the Recipe Settings gear and select `Show Nutritional Values` +4. Scroll down to manually fill out the Nutritional Values +5. Save + +### Show Nutritional Values by default +1. Click your username in the top left +2. Click the 'Household Settings' button +3. Under 'Household Recipe Preferences', click to select 'Show nutrition information' +4. Click 'Update' + ## Is it safe to upgrade Mealie? Yes. If you are using the v1 branches (including beta), you can upgrade to the latest version of Mealie without performing a site Export/Restore. This process was required in previous versions of Mealie, however we've automated the database migration process to make it easier to upgrade. Note that if you were using the v0.5.x version, you CANNOT upgrade to the latest version automatically. You must follow the migration instructions in the documentation. From 7f99e2fc36d34e1506e99d1055d367ecf9d0fdff Mon Sep 17 00:00:00 2001 From: Chip Date: Mon, 13 Jan 2025 10:19:27 -0500 Subject: [PATCH 06/45] docs: Fix Spelling Errors on Nutritional Values (#4888) --- docs/docs/documentation/getting-started/faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/documentation/getting-started/faq.md b/docs/docs/documentation/getting-started/faq.md index 27f63136a..a8f2f28e8 100644 --- a/docs/docs/documentation/getting-started/faq.md +++ b/docs/docs/documentation/getting-started/faq.md @@ -33,8 +33,8 @@ Do the following for each recipe you want to intelligently handle ingredients. Scaling up this recipe or adding it to a Shopping List will now smartly take care of ingredient amounts and duplicate combinations. -## How do I enable Nutrtional Values? -Mealie can store Nutritional Information for Recipes. Please note that the values you enter are static for the recipe and no scaling is being done when channging Servings / Yield. +## How do I enable Nutritional Values? +Mealie can store Nutritional Information for Recipes. Please note that the values you enter are static for the recipe and no scaling is being done when changing Servings / Yield. Do the following to enable Nutritional Values on individual Recipes, or to modify your Household Recipe Preferences From ea0bec23366d9116410912544290797f2d1f29bf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:31:42 +0000 Subject: [PATCH 07/45] chore(auto): Update pre-commit hooks (#4886) Co-authored-by: boc-the-git <3479092+boc-the-git@users.noreply.github.com> Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8696d87f2..15b353d9c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: exclude: ^tests/data/ - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.8.6 + rev: v0.9.1 hooks: - id: ruff - id: ruff-format From 2c2de1e95b13e1c838ab43759c592497d2c06824 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:43:55 +0000 Subject: [PATCH 08/45] chore(deps): update dependency ruff to ^0.9.0 (#4871) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com> Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- mealie/db/fixes/fix_group_with_no_name.py | 3 +- mealie/db/fixes/fix_migration_data.py | 4 +- mealie/repos/repository_cookbooks.py | 4 +- mealie/services/migrations/tandoor.py | 2 +- mealie/services/scraper/cleaner.py | 20 ++-------- poetry.lock | 40 +++++++++---------- pyproject.toml | 2 +- .../test_group_mealplan.py | 34 ++++++++-------- .../test_group_webhooks.py | 6 +-- .../test_recipe_bulk_action.py | 3 +- .../test_recipe_cross_household.py | 4 +- .../user_recipe_tests/test_recipe_owner.py | 4 +- .../repository_tests/test_pagination.py | 16 ++++---- .../test_recipe_repository.py | 24 +++++------ .../repository_tests/test_search.py | 6 +-- .../tasks/test_create_timeline_events.py | 34 ++++++++-------- ..._delete_old_checked_shopping_list_items.py | 4 +- .../scheduler/tasks/test_post_webhook.py | 30 +++++++------- .../user_services/test_user_service.py | 6 +-- tests/unit_tests/test_alembic.py | 6 +-- .../validator_tests/test_create_plan_entry.py | 8 ++-- 22 files changed, 124 insertions(+), 138 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 15b353d9c..acbc1c120 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: exclude: ^tests/data/ - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.9.1 + rev: v0.9.0 hooks: - id: ruff - id: ruff-format diff --git a/mealie/db/fixes/fix_group_with_no_name.py b/mealie/db/fixes/fix_group_with_no_name.py index 992c5483b..e367d1c3a 100644 --- a/mealie/db/fixes/fix_group_with_no_name.py +++ b/mealie/db/fixes/fix_group_with_no_name.py @@ -26,8 +26,7 @@ def fix_group_with_no_name(session: Session): return logger.info( - f'{len(groups)} {"group" if len(groups) == 1 else "groups"} found with a missing name; ' - f"applying default name" + f"{len(groups)} {'group' if len(groups) == 1 else 'groups'} found with a missing name; applying default name" ) offset = 0 diff --git a/mealie/db/fixes/fix_migration_data.py b/mealie/db/fixes/fix_migration_data.py index 200b160d5..2ec83cae2 100644 --- a/mealie/db/fixes/fix_migration_data.py +++ b/mealie/db/fixes/fix_migration_data.py @@ -51,7 +51,7 @@ def fix_dangling_refs(session: Session): if result.rowcount: logger.info( - f'Reassigned {result.rowcount} {"row" if result.rowcount == 1 else "rows"} ' + f"Reassigned {result.rowcount} {'row' if result.rowcount == 1 else 'rows'} " f'in "{table_name}" table to default user ({default_user.id})' ) @@ -63,7 +63,7 @@ def fix_dangling_refs(session: Session): if result.rowcount: logger.info( - f'Deleted {result.rowcount} {"row" if result.rowcount == 1 else "rows"} ' + f"Deleted {result.rowcount} {'row' if result.rowcount == 1 else 'rows'} " f'in "{table_name}" table with invalid user ids' ) diff --git a/mealie/repos/repository_cookbooks.py b/mealie/repos/repository_cookbooks.py index d453c3f70..4a42f390c 100644 --- a/mealie/repos/repository_cookbooks.py +++ b/mealie/repos/repository_cookbooks.py @@ -24,7 +24,7 @@ class RepositoryCookbooks(HouseholdRepositoryGeneric[ReadCookBook, CookBook]): return super().create(data) except IntegrityError: self.session.rollback() - data.slug = slugify(f"{data.name} ({i+1})") + data.slug = slugify(f"{data.name} ({i + 1})") raise # raise the last IntegrityError @@ -45,7 +45,7 @@ class RepositoryCookbooks(HouseholdRepositoryGeneric[ReadCookBook, CookBook]): return super().update(match_value, data) except IntegrityError: self.session.rollback() - data.slug = slugify(f"{data.name} ({i+1})") + data.slug = slugify(f"{data.name} ({i + 1})") raise # raise the last IntegrityError diff --git a/mealie/services/migrations/tandoor.py b/mealie/services/migrations/tandoor.py index ba8979245..ef78698ab 100644 --- a/mealie/services/migrations/tandoor.py +++ b/mealie/services/migrations/tandoor.py @@ -112,7 +112,7 @@ class TandoorMigrator(BaseMigrator): recipes_as_dicts: list[dict] = [] for i, recipe_zip_file in enumerate(source_dir.glob("*.zip")): try: - recipe_dir = str(source_dir.joinpath(f"recipe_{i+1}")) + recipe_dir = str(source_dir.joinpath(f"recipe_{i + 1}")) os.makedirs(recipe_dir) with zipfile.ZipFile(recipe_zip_file) as recipe_zip: diff --git a/mealie/services/scraper/cleaner.py b/mealie/services/scraper/cleaner.py index 1089008c4..b5acb88b7 100644 --- a/mealie/services/scraper/cleaner.py +++ b/mealie/services/scraper/cleaner.py @@ -129,10 +129,7 @@ def clean_image(image: str | list | dict | None = None, default: str = "no image case [{"@id": str(_)}, *_]: return [x["@id"] for x in image if "@id" in x] case _: - logger.exception( - f"Unexpected type for image: { - type(image)}, {image}" - ) + logger.exception(f"Unexpected type for image: {type(image)}, {image}") return [default] @@ -227,10 +224,7 @@ def clean_instructions(steps_object: list | dict | str, default: list | None = N ) ) case _: - raise TypeError( - f"Unexpected type for instructions: { - type(steps_object)}, {steps_object}" - ) + raise TypeError(f"Unexpected type for instructions: {type(steps_object)}, {steps_object}") def _sanitize_instruction_text(line: str | dict) -> str: @@ -290,10 +284,7 @@ def clean_ingredients(ingredients: list | str | None, default: list | None = Non case str(ingredients): return [clean_string(ingredient) for ingredient in ingredients.splitlines() if ingredient.strip()] case _: - raise TypeError( - f"Unexpected type for ingredients: { - type(ingredients)}, {ingredients}" - ) + raise TypeError(f"Unexpected type for ingredients: {type(ingredients)}, {ingredients}") def clean_int(val: str | int | None, min: int | None = None, max: int | None = None): @@ -531,10 +522,7 @@ def clean_categories(category: str | list) -> list[str]: # return [cat["name"] for cat in category if "name" in cat] case _: - raise TypeError( - f"Unexpected type for category: { - type(category)}, {category}" - ) + raise TypeError(f"Unexpected type for category: {type(category)}, {category}") def clean_tags(data: str | list[str]) -> list[str]: diff --git a/poetry.lock b/poetry.lock index 3da9f6aac..3ed33307c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2828,29 +2828,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.8.6" +version = "0.9.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3"}, - {file = "ruff-0.8.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1"}, - {file = "ruff-0.8.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf"}, - {file = "ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117"}, - {file = "ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe"}, - {file = "ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d"}, - {file = "ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a"}, - {file = "ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76"}, - {file = "ruff-0.8.6-py3-none-win32.whl", hash = "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764"}, - {file = "ruff-0.8.6-py3-none-win_amd64.whl", hash = "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905"}, - {file = "ruff-0.8.6-py3-none-win_arm64.whl", hash = "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162"}, - {file = "ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5"}, + {file = "ruff-0.9.0-py3-none-linux_armv6l.whl", hash = "sha256:949b3513f931741e006cf267bf89611edff04e1f012013424022add3ce78f319"}, + {file = "ruff-0.9.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:99fbcb8c7fe94ae1e462ab2a1ef17cb20b25fb6438b9f198b1bcf5207a0a7916"}, + {file = "ruff-0.9.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b022afd8eb0fcfce1e0adec84322abf4d6ce3cd285b3b99c4f17aae7decf749"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:336567ce92c9ca8ec62780d07b5fa11fbc881dc7bb40958f93a7d621e7ab4589"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d338336c44bda602dc8e8766836ac0441e5b0dfeac3af1bd311a97ebaf087a75"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9b3ececf523d733e90b540e7afcc0494189e8999847f8855747acd5a9a8c45f"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a11c0872a31232e473e2e0e2107f3d294dbadd2f83fb281c3eb1c22a24866924"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5fd06220c17a9cc0dc7fc6552f2ac4db74e8e8bff9c401d160ac59d00566f54"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0457e775c74bf3976243f910805242b7dcd389e1d440deccbd1194ca17a5728c"}, + {file = "ruff-0.9.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05415599bbcb318f730ea1b46a39e4fbf71f6a63fdbfa1dda92efb55f19d7ecf"}, + {file = "ruff-0.9.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fbf9864b009e43cfc1c8bed1a6a4c529156913105780af4141ca4342148517f5"}, + {file = "ruff-0.9.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:37b3da222b12e2bb2ce628e02586ab4846b1ed7f31f42a5a0683b213453b2d49"}, + {file = "ruff-0.9.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:733c0fcf2eb0c90055100b4ed1af9c9d87305b901a8feb6a0451fa53ed88199d"}, + {file = "ruff-0.9.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8221a454bfe5ccdf8017512fd6bb60e6ec30f9ea252b8a80e5b73619f6c3cefd"}, + {file = "ruff-0.9.0-py3-none-win32.whl", hash = "sha256:d345f2178afd192c7991ddee59155c58145e12ad81310b509bd2e25c5b0247b3"}, + {file = "ruff-0.9.0-py3-none-win_amd64.whl", hash = "sha256:0cbc0905d94d21305872f7f8224e30f4bbcd532bc21b2225b2446d8fc7220d19"}, + {file = "ruff-0.9.0-py3-none-win_arm64.whl", hash = "sha256:7b1148771c6ca88f820d761350a053a5794bc58e0867739ea93eb5e41ad978cd"}, + {file = "ruff-0.9.0.tar.gz", hash = "sha256:143f68fa5560ecf10fc49878b73cee3eab98b777fcf43b0e62d43d42f5ef9d8b"}, ] [[package]] @@ -3421,4 +3421,4 @@ pgsql = ["psycopg2-binary"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "ee922a45c721fc906d1b41e9b693211c57795900e05f59fdf802e1c2d7481bef" +content-hash = "1561f8552de2253187d19299bb098f0ab53b1def90a0fa121a3cba379d5b0da8" diff --git a/pyproject.toml b/pyproject.toml index 0421a0802..aa4e1ba29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,7 +64,7 @@ pylint = "^3.0.0" pytest = "^8.0.0" pytest-asyncio = "^0.25.0" rich = "^13.5.2" -ruff = "^0.8.0" +ruff = "^0.9.0" types-PyYAML = "^6.0.4" types-python-dateutil = "^2.8.18" types-python-slugify = "^6.0.0" diff --git a/tests/integration_tests/user_household_tests/test_group_mealplan.py b/tests/integration_tests/user_household_tests/test_group_mealplan.py index 664ead9a2..f78b0eb86 100644 --- a/tests/integration_tests/user_household_tests/test_group_mealplan.py +++ b/tests/integration_tests/user_household_tests/test_group_mealplan.py @@ -1,5 +1,5 @@ import random -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from uuid import UUID from fastapi.testclient import TestClient @@ -42,11 +42,11 @@ def create_rule( ): qf_parts: list[str] = [] if tags: - qf_parts.append(f'tags.id CONTAINS ALL [{",".join([str(tag.id) for tag in tags])}]') + qf_parts.append(f"tags.id CONTAINS ALL [{','.join([str(tag.id) for tag in tags])}]") if categories: - qf_parts.append(f'recipe_category.id CONTAINS ALL [{",".join([str(cat.id) for cat in categories])}]') + qf_parts.append(f"recipe_category.id CONTAINS ALL [{','.join([str(cat.id) for cat in categories])}]") if households: - qf_parts.append(f'household_id IN [{",".join([str(household.id) for household in households])}]') + qf_parts.append(f"household_id IN [{','.join([str(household.id) for household in households])}]") query_filter_string = " AND ".join(qf_parts) return unique_user.repos.group_meal_plan_rules.create( @@ -64,9 +64,9 @@ def test_create_mealplan_no_recipe(api_client: TestClient, unique_user: TestUser title = random_string(length=25) text = random_string(length=25) new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="breakfast", title=title, text=text + date=datetime.now(UTC).date(), entry_type="breakfast", title=title, text=text ).model_dump() - new_plan["date"] = datetime.now(timezone.utc).date().strftime("%Y-%m-%d") + new_plan["date"] = datetime.now(UTC).date().strftime("%Y-%m-%d") response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) @@ -86,10 +86,10 @@ def test_create_mealplan_with_recipe(api_client: TestClient, unique_user: TestUs recipe = response.json() recipe_id = recipe["id"] - new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="dinner", recipe_id=recipe_id - ).model_dump(by_alias=True) - new_plan["date"] = datetime.now(timezone.utc).date().strftime("%Y-%m-%d") + new_plan = CreatePlanEntry(date=datetime.now(UTC).date(), entry_type="dinner", recipe_id=recipe_id).model_dump( + by_alias=True + ) + new_plan["date"] = datetime.now(UTC).date().strftime("%Y-%m-%d") new_plan["recipeId"] = str(recipe_id) response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) @@ -101,14 +101,14 @@ def test_create_mealplan_with_recipe(api_client: TestClient, unique_user: TestUs def test_crud_mealplan(api_client: TestClient, unique_user: TestUser): new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), + date=datetime.now(UTC).date(), entry_type="breakfast", title=random_string(), text=random_string(), ).model_dump() # Create - new_plan["date"] = datetime.now(timezone.utc).date().strftime("%Y-%m-%d") + new_plan["date"] = datetime.now(UTC).date().strftime("%Y-%m-%d") response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) response_json = response.json() assert response.status_code == 201 @@ -139,13 +139,13 @@ def test_crud_mealplan(api_client: TestClient, unique_user: TestUser): def test_get_all_mealplans(api_client: TestClient, unique_user: TestUser): for _ in range(3): new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), + date=datetime.now(UTC).date(), entry_type="breakfast", title=random_string(), text=random_string(), ).model_dump() - new_plan["date"] = datetime.now(timezone.utc).date().strftime("%Y-%m-%d") + new_plan["date"] = datetime.now(UTC).date().strftime("%Y-%m-%d") response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) assert response.status_code == 201 @@ -159,7 +159,7 @@ def test_get_all_mealplans(api_client: TestClient, unique_user: TestUser): def test_get_slice_mealplans(api_client: TestClient, unique_user: TestUser): # Make List of 10 dates from now to +10 days - dates = [datetime.now(timezone.utc).date() + timedelta(days=x) for x in range(10)] + dates = [datetime.now(UTC).date() + timedelta(days=x) for x in range(10)] # Make a list of 10 meal plans meal_plans = [ @@ -193,7 +193,7 @@ def test_get_mealplan_today(api_client: TestClient, unique_user: TestUser): # Create Meal Plans for today test_meal_plans = [ CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="breakfast", title=random_string(), text=random_string() + date=datetime.now(UTC).date(), entry_type="breakfast", title=random_string(), text=random_string() ).model_dump() for _ in range(3) ] @@ -212,7 +212,7 @@ def test_get_mealplan_today(api_client: TestClient, unique_user: TestUser): response_json = response.json() for meal_plan in response_json: - assert meal_plan["date"] == datetime.now(timezone.utc).date().strftime("%Y-%m-%d") + assert meal_plan["date"] == datetime.now(UTC).date().strftime("%Y-%m-%d") def test_get_mealplan_with_rules_categories_and_tags_filter(api_client: TestClient, unique_user: TestUser): diff --git a/tests/integration_tests/user_household_tests/test_group_webhooks.py b/tests/integration_tests/user_household_tests/test_group_webhooks.py index dac4d01bb..3dd7d87b5 100644 --- a/tests/integration_tests/user_household_tests/test_group_webhooks.py +++ b/tests/integration_tests/user_household_tests/test_group_webhooks.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest from fastapi.testclient import TestClient @@ -14,7 +14,7 @@ def webhook_data(): "name": "Test-Name", "url": "https://my-fake-url.com", "time": "00:00", - "scheduledTime": datetime.now(timezone.utc), + "scheduledTime": datetime.now(UTC), } @@ -41,7 +41,7 @@ def test_read_webhook(api_client: TestClient, unique_user: TestUser, webhook_dat assert webhook["id"] == item_id assert webhook["name"] == webhook_data["name"] assert webhook["url"] == webhook_data["url"] - assert webhook["scheduledTime"] == str(webhook_data["scheduledTime"].astimezone(timezone.utc).time()) + assert webhook["scheduledTime"] == str(webhook_data["scheduledTime"].astimezone(UTC).time()) assert webhook["enabled"] == webhook_data["enabled"] diff --git a/tests/integration_tests/user_recipe_tests/test_recipe_bulk_action.py b/tests/integration_tests/user_recipe_tests/test_recipe_bulk_action.py index d952ac936..3b2d2cea8 100644 --- a/tests/integration_tests/user_recipe_tests/test_recipe_bulk_action.py +++ b/tests/integration_tests/user_recipe_tests/test_recipe_bulk_action.py @@ -6,7 +6,6 @@ import sqlalchemy from fastapi.testclient import TestClient from mealie.core.dependencies.dependencies import validate_file_token -from mealie.repos.repository_factory import AllRepositories from mealie.schema.recipe.recipe_bulk_actions import ExportTypes from mealie.schema.recipe.recipe_category import CategorySave, TagSave from tests import utils @@ -137,7 +136,7 @@ def test_bulk_export_recipes(api_client: TestClient, unique_user: TestUser, ten_ assert validate_file_token(response_data["fileToken"]) == Path(export_path) # Use Export Token to download export - response = api_client.get(f'/api/utils/download?token={response_data["fileToken"]}') + response = api_client.get(f"/api/utils/download?token={response_data['fileToken']}") assert response.status_code == 200 diff --git a/tests/integration_tests/user_recipe_tests/test_recipe_cross_household.py b/tests/integration_tests/user_recipe_tests/test_recipe_cross_household.py index fa6b58aba..700a6d8c0 100644 --- a/tests/integration_tests/user_recipe_tests/test_recipe_cross_household.py +++ b/tests/integration_tests/user_recipe_tests/test_recipe_cross_household.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest from fastapi.testclient import TestClient @@ -242,7 +242,7 @@ def test_user_can_update_last_made_on_other_household( assert recipe["id"] == str(h2_recipe_id) old_last_made = recipe["lastMade"] - now = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") + now = datetime.now(UTC).isoformat().replace("+00:00", "Z") response = api_client.patch( api_routes.recipes_slug_last_made(h2_recipe_slug), json={"timestamp": now}, headers=unique_user.token ) diff --git a/tests/integration_tests/user_recipe_tests/test_recipe_owner.py b/tests/integration_tests/user_recipe_tests/test_recipe_owner.py index 86913b398..3b6372281 100644 --- a/tests/integration_tests/user_recipe_tests/test_recipe_owner.py +++ b/tests/integration_tests/user_recipe_tests/test_recipe_owner.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from fastapi.testclient import TestClient @@ -106,7 +106,7 @@ def test_user_update_last_made(api_client: TestClient, user_tuple: list[TestUser response = api_client.put(api_routes.recipes + f"/{recipe_name}", json=recipe, headers=usr_1.token) # User 2 should be able to update the last made timestamp - last_made_json = {"timestamp": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")} + last_made_json = {"timestamp": datetime.now(UTC).isoformat().replace("+00:00", "Z")} response = api_client.patch( api_routes.recipes_slug_last_made(recipe_name), json=last_made_json, headers=usr_2.token ) diff --git a/tests/unit_tests/repository_tests/test_pagination.py b/tests/unit_tests/repository_tests/test_pagination.py index 528d77419..36e3c3d3b 100644 --- a/tests/unit_tests/repository_tests/test_pagination.py +++ b/tests/unit_tests/repository_tests/test_pagination.py @@ -1,7 +1,7 @@ import random import time from collections import defaultdict -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from random import randint from urllib.parse import parse_qsl, urlsplit @@ -238,7 +238,7 @@ def test_pagination_filter_null(unique_user: TestUser): user_id=unique_user.user_id, group_id=unique_user.group_id, name=random_string(), - last_made=datetime.now(timezone.utc), + last_made=datetime.now(UTC), ) ) @@ -626,7 +626,7 @@ def test_pagination_filter_datetimes( ) def test_pagination_order_by_multiple(unique_user: TestUser, order_direction: OrderDirection): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) alphabet = ["a", "b", "c", "d", "e"] abbreviations = alphabet.copy() @@ -687,7 +687,7 @@ def test_pagination_order_by_multiple_directions( unique_user: TestUser, order_by_str: str, order_direction: OrderDirection ): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) alphabet = ["a", "b", "c", "d", "e"] abbreviations = alphabet.copy() @@ -735,7 +735,7 @@ def test_pagination_order_by_multiple_directions( ) def test_pagination_order_by_nested_model(unique_user: TestUser, order_direction: OrderDirection): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) alphabet = ["a", "b", "c", "d", "e"] labels = database.group_multi_purpose_labels.create_many( @@ -766,7 +766,7 @@ def test_pagination_order_by_nested_model(unique_user: TestUser, order_direction def test_pagination_order_by_doesnt_filter(unique_user: TestUser): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) label = database.group_multi_purpose_labels.create( MultiPurposeLabelSave(name=random_string(), group_id=unique_user.group_id) @@ -810,7 +810,7 @@ def test_pagination_order_by_nulls( unique_user: TestUser, null_position: OrderByNullPosition, order_direction: OrderDirection ): database = unique_user.repos - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) label = database.group_multi_purpose_labels.create( MultiPurposeLabelSave(name=random_string(), group_id=unique_user.group_id) @@ -916,7 +916,7 @@ def test_pagination_shopping_list_items_with_labels(unique_user: TestUser): def test_pagination_filter_dates(api_client: TestClient, unique_user: TestUser): - today = datetime.now(timezone.utc).date() + today = datetime.now(UTC).date() yesterday = today - timedelta(days=1) tomorrow = today + timedelta(days=1) diff --git a/tests/unit_tests/repository_tests/test_recipe_repository.py b/tests/unit_tests/repository_tests/test_recipe_repository.py index 9c9dde4f4..8b4c2ddf6 100644 --- a/tests/unit_tests/repository_tests/test_recipe_repository.py +++ b/tests/unit_tests/repository_tests/test_recipe_repository.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import cast from uuid import UUID @@ -340,12 +340,12 @@ def test_recipe_repo_pagination_by_categories(unique_user: TestUser): page=1, per_page=-1, order_by="random", - pagination_seed=str(datetime.now(timezone.utc)), + pagination_seed=str(datetime.now(UTC)), order_direction=OrderDirection.asc, ) random_ordered = [] for _ in range(5): - pagination_query.pagination_seed = str(datetime.now(timezone.utc)) + pagination_query.pagination_seed = str(datetime.now(UTC)) random_ordered.append(database.recipes.page_all(pagination_query, categories=[category_slug]).items) assert not all(i == random_ordered[0] for i in random_ordered) @@ -437,12 +437,12 @@ def test_recipe_repo_pagination_by_tags(unique_user: TestUser): page=1, per_page=-1, order_by="random", - pagination_seed=str(datetime.now(timezone.utc)), + pagination_seed=str(datetime.now(UTC)), order_direction=OrderDirection.asc, ) random_ordered = [] for _ in range(5): - pagination_query.pagination_seed = str(datetime.now(timezone.utc)) + pagination_query.pagination_seed = str(datetime.now(UTC)) random_ordered.append(database.recipes.page_all(pagination_query, tags=[tag_slug]).items) assert len(random_ordered[0]) == 15 assert not all(i == random_ordered[0] for i in random_ordered) @@ -534,12 +534,12 @@ def test_recipe_repo_pagination_by_tools(unique_user: TestUser): page=1, per_page=-1, order_by="random", - pagination_seed=str(datetime.now(timezone.utc)), + pagination_seed=str(datetime.now(UTC)), order_direction=OrderDirection.asc, ) random_ordered = [] for _ in range(5): - pagination_query.pagination_seed = str(datetime.now(timezone.utc)) + pagination_query.pagination_seed = str(datetime.now(UTC)) random_ordered.append(database.recipes.page_all(pagination_query, tools=[tool_id]).items) assert len(random_ordered[0]) == 15 assert not all(i == random_ordered[0] for i in random_ordered) @@ -619,12 +619,12 @@ def test_recipe_repo_pagination_by_foods(unique_user: TestUser): page=1, per_page=-1, order_by="random", - pagination_seed=str(datetime.now(timezone.utc)), + pagination_seed=str(datetime.now(UTC)), order_direction=OrderDirection.asc, ) random_ordered = [] for _ in range(5): - pagination_query.pagination_seed = str(datetime.now(timezone.utc)) + pagination_query.pagination_seed = str(datetime.now(UTC)) random_ordered.append(database.recipes.page_all(pagination_query, foods=[food_id]).items) assert len(random_ordered[0]) == 15 assert not all(i == random_ordered[0] for i in random_ordered) @@ -696,12 +696,12 @@ def test_random_order_recipe_search( page=1, per_page=-1, order_by="random", - pagination_seed=str(datetime.now(timezone.utc)), + pagination_seed=str(datetime.now(UTC)), order_direction=OrderDirection.asc, ) random_ordered = [] for _ in range(5): - pagination.pagination_seed = str(datetime.now(timezone.utc)) + pagination.pagination_seed = str(datetime.now(UTC)) random_ordered.append(repo.page_all(pagination, search="soup").items) assert not all(i == random_ordered[0] for i in random_ordered) @@ -713,7 +713,7 @@ def test_order_by_rating(user_tuple: tuple[TestUser, TestUser]): recipes: list[Recipe] = [] for i in range(3): - slug = f"recipe-{i+1}-{random_string(5)}" + slug = f"recipe-{i + 1}-{random_string(5)}" recipes.append( repo.create( Recipe( diff --git a/tests/unit_tests/repository_tests/test_search.py b/tests/unit_tests/repository_tests/test_search.py index eb9da4317..461d28d32 100644 --- a/tests/unit_tests/repository_tests/test_search.py +++ b/tests/unit_tests/repository_tests/test_search.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest from sqlalchemy.orm import Session @@ -129,11 +129,11 @@ def test_random_order_search( page=1, per_page=-1, order_by="random", - pagination_seed=str(datetime.now(timezone.utc)), + pagination_seed=str(datetime.now(UTC)), order_direction=OrderDirection.asc, ) random_ordered = [] for _ in range(5): - pagination.pagination_seed = str(datetime.now(timezone.utc)) + pagination.pagination_seed = str(datetime.now(UTC)) random_ordered.append(repo.page_all(pagination, search="unit").items) assert not all(i == random_ordered[0] for i in random_ordered) diff --git a/tests/unit_tests/services_tests/scheduler/tasks/test_create_timeline_events.py b/tests/unit_tests/services_tests/scheduler/tasks/test_create_timeline_events.py index d3ef48866..9dbe7145d 100644 --- a/tests/unit_tests/services_tests/scheduler/tasks/test_create_timeline_events.py +++ b/tests/unit_tests/services_tests/scheduler/tasks/test_create_timeline_events.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from fastapi.testclient import TestClient from pydantic import UUID4 @@ -34,10 +34,10 @@ def test_new_mealplan_event(api_client: TestClient, unique_user: TestUser): response_json = response.json() initial_event_count = len(response_json["items"]) - new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="dinner", recipe_id=recipe_id - ).model_dump(by_alias=True) - new_plan["date"] = datetime.now(timezone.utc).date().isoformat() + new_plan = CreatePlanEntry(date=datetime.now(UTC).date(), entry_type="dinner", recipe_id=recipe_id).model_dump( + by_alias=True + ) + new_plan["date"] = datetime.now(UTC).date().isoformat() new_plan["recipeId"] = str(recipe_id) response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) @@ -65,7 +65,7 @@ def test_new_mealplan_event(api_client: TestClient, unique_user: TestUser): response = api_client.get(api_routes.recipes_slug(recipe_name), headers=unique_user.token) new_recipe_data: dict = response.json() recipe = RecipeSummary.model_validate(new_recipe_data) - assert recipe.last_made.date() == datetime.now(timezone.utc).date() # type: ignore + assert recipe.last_made.date() == datetime.now(UTC).date() # type: ignore # make sure nothing else was updated for data in [original_recipe_data, new_recipe_data]: @@ -101,10 +101,10 @@ def test_new_mealplan_event_duplicates(api_client: TestClient, unique_user: Test response_json = response.json() initial_event_count = len(response_json["items"]) - new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="dinner", recipe_id=recipe_id - ).model_dump(by_alias=True) - new_plan["date"] = datetime.now(timezone.utc).date().isoformat() + new_plan = CreatePlanEntry(date=datetime.now(UTC).date(), entry_type="dinner", recipe_id=recipe_id).model_dump( + by_alias=True + ) + new_plan["date"] = datetime.now(UTC).date().isoformat() new_plan["recipeId"] = str(recipe_id) response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) @@ -148,9 +148,9 @@ def test_new_mealplan_events_with_multiple_recipes(api_client: TestClient, uniqu mealplan_count_by_recipe_id[recipe.id] = 0 # type: ignore for _ in range(random_int(1, 5)): new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="dinner", recipe_id=str(recipe.id) + date=datetime.now(UTC).date(), entry_type="dinner", recipe_id=str(recipe.id) ).model_dump(by_alias=True) - new_plan["date"] = datetime.now(timezone.utc).date().isoformat() + new_plan["date"] = datetime.now(UTC).date().isoformat() new_plan["recipeId"] = str(recipe.id) response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) @@ -200,17 +200,17 @@ def test_preserve_future_made_date(api_client: TestClient, unique_user: TestUser recipe = RecipeSummary.model_validate(response.json()) recipe_id = str(recipe.id) - future_dt = datetime.now(timezone.utc) + timedelta(days=random_int(1, 10)) + future_dt = datetime.now(UTC) + timedelta(days=random_int(1, 10)) recipe.last_made = future_dt response = api_client.put( api_routes.recipes_slug(recipe.slug), json=utils.jsonify(recipe), headers=unique_user.token ) assert response.status_code == 200 - new_plan = CreatePlanEntry( - date=datetime.now(timezone.utc).date(), entry_type="dinner", recipe_id=recipe_id - ).model_dump(by_alias=True) - new_plan["date"] = datetime.now(timezone.utc).date().isoformat() + new_plan = CreatePlanEntry(date=datetime.now(UTC).date(), entry_type="dinner", recipe_id=recipe_id).model_dump( + by_alias=True + ) + new_plan["date"] = datetime.now(UTC).date().isoformat() new_plan["recipeId"] = str(recipe_id) response = api_client.post(api_routes.households_mealplans, json=new_plan, headers=unique_user.token) diff --git a/tests/unit_tests/services_tests/scheduler/tasks/test_delete_old_checked_shopping_list_items.py b/tests/unit_tests/services_tests/scheduler/tasks/test_delete_old_checked_shopping_list_items.py index 34e435205..782814670 100644 --- a/tests/unit_tests/services_tests/scheduler/tasks/test_delete_old_checked_shopping_list_items.py +++ b/tests/unit_tests/services_tests/scheduler/tasks/test_delete_old_checked_shopping_list_items.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from mealie.schema.household.group_shopping_list import ShoppingListItemCreate, ShoppingListItemOut, ShoppingListSave from mealie.services.scheduler.tasks.delete_old_checked_shopping_list_items import ( @@ -44,7 +44,7 @@ def test_cleanup(unique_user: TestUser): for item in unchecked_items + checked_items: assert item in shopping_list.list_items - checked_items.sort(key=lambda x: x.updated_at or datetime.now(timezone.utc), reverse=True) + checked_items.sort(key=lambda x: x.updated_at or datetime.now(UTC), reverse=True) expected_kept_items = unchecked_items + checked_items[:MAX_CHECKED_ITEMS] expected_deleted_items = checked_items[MAX_CHECKED_ITEMS:] diff --git a/tests/unit_tests/services_tests/scheduler/tasks/test_post_webhook.py b/tests/unit_tests/services_tests/scheduler/tasks/test_post_webhook.py index 6a218d322..d56c5c52c 100644 --- a/tests/unit_tests/services_tests/scheduler/tasks/test_post_webhook.py +++ b/tests/unit_tests/services_tests/scheduler/tasks/test_post_webhook.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from uuid import UUID from pydantic import UUID4 @@ -31,7 +31,7 @@ def webhook_factory( name=name or random_string(), url=url or random_string(), webhook_type=webhook_type, - scheduled_time=scheduled_time.time() if scheduled_time else datetime.now(timezone.utc).time(), + scheduled_time=scheduled_time.time() if scheduled_time else datetime.now(UTC).time(), group_id=group_id, household_id=household_id, ) @@ -45,7 +45,7 @@ def test_get_scheduled_webhooks_filter_query(unique_user: TestUser): database = unique_user.repos expected: list[SaveWebhook] = [] - start = datetime.now(timezone.utc) + start = datetime.now(UTC) for _ in range(5): new_item = webhook_factory( @@ -65,7 +65,7 @@ def test_get_scheduled_webhooks_filter_query(unique_user: TestUser): expected.append(new_item) event_bus_listener = WebhookEventListener(UUID(unique_user.group_id), UUID(unique_user.household_id)) - results = event_bus_listener.get_scheduled_webhooks(start, datetime.now(timezone.utc) + timedelta(minutes=5)) + results = event_bus_listener.get_scheduled_webhooks(start, datetime.now(UTC) + timedelta(minutes=5)) assert len(results) == len(expected) @@ -85,8 +85,8 @@ def test_event_listener_get_meals_by_date_range(unique_user: TestUser): """ meal_repo = unique_user.repos.meals - start_date = datetime.now(timezone.utc) - timedelta(days=7) - end_date = datetime.now(timezone.utc) + start_date = datetime.now(UTC) - timedelta(days=7) + end_date = datetime.now(UTC) meal_1 = meal_repo.create( { @@ -152,8 +152,8 @@ def test_event_listener_get_meals_by_date_range(unique_user: TestUser): def test_get_meals_by_date_range(unique_user: TestUser): meal_repo = unique_user.repos.meals - start_date = datetime.now(timezone.utc) - timedelta(days=7) - end_date = datetime.now(timezone.utc) + start_date = datetime.now(UTC) - timedelta(days=7) + end_date = datetime.now(UTC) meal_1 = meal_repo.create( { @@ -210,8 +210,8 @@ def test_get_meals_by_date_range_no_meals(unique_user: TestUser): """ meal_repo = unique_user.repos.meals - start_date = datetime.now(timezone.utc) - timedelta(days=7) - end_date = datetime.now(timezone.utc) + start_date = datetime.now(UTC) - timedelta(days=7) + end_date = datetime.now(UTC) meals_in_range = meal_repo.get_meals_by_date_range(start_date, end_date) @@ -224,7 +224,7 @@ def test_get_meals_by_date_range_single_day(unique_user: TestUser): """ meal_repo = unique_user.repos.meals - single_day = datetime.now(timezone.utc) + single_day = datetime.now(UTC) meal_1 = meal_repo.create( { @@ -255,12 +255,12 @@ def test_get_meals_by_date_range_no_overlap(unique_user: TestUser): """ meal_repo = unique_user.repos.meals - start_date = datetime.now(timezone.utc) + timedelta(days=1) - end_date = datetime.now(timezone.utc) + timedelta(days=10) + start_date = datetime.now(UTC) + timedelta(days=1) + end_date = datetime.now(UTC) + timedelta(days=10) meal_1 = meal_repo.create( { - "date": datetime.now(timezone.utc) - timedelta(days=5), + "date": datetime.now(UTC) - timedelta(days=5), "entry_type": "dinner", "title": "Meal Outside Range", "text": "This meal is outside the tested date range", @@ -289,7 +289,7 @@ def test_get_meals_by_date_range_invalid_date_range(unique_user: TestUser): """ meal_repo = unique_user.repos.meals - start_date = datetime.now(timezone.utc) + start_date = datetime.now(UTC) end_date = start_date - timedelta(days=1) meals_in_range = meal_repo.get_meals_by_date_range(start_date, end_date) diff --git a/tests/unit_tests/services_tests/user_services/test_user_service.py b/tests/unit_tests/services_tests/user_services/test_user_service.py index 279932715..81e1235d5 100644 --- a/tests/unit_tests/services_tests/user_services/test_user_service.py +++ b/tests/unit_tests/services_tests/user_services/test_user_service.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta import pytest @@ -65,7 +65,7 @@ def test_lock_unlocker_user(unique_user: TestUser) -> None: assert not unlocked_user.is_locked # Sanity check that the is_locked property is working - user.locked_at = datetime.now(timezone.utc) - timedelta(days=2) + user.locked_at = datetime.now(UTC) - timedelta(days=2) assert not user.is_locked @@ -98,7 +98,7 @@ def test_reset_locked_users(unique_user: TestUser, use_task: bool) -> None: assert user.login_attemps == 5 # Test that the locked user is unlocked by reset - user.locked_at = datetime.now(timezone.utc) - timedelta(days=2) + user.locked_at = datetime.now(UTC) - timedelta(days=2) database.users.update(user.id, user) if use_task: unlocked = locked_user_reset() diff --git a/tests/unit_tests/test_alembic.py b/tests/unit_tests/test_alembic.py index 1bcc621ff..7ded6c732 100644 --- a/tests/unit_tests/test_alembic.py +++ b/tests/unit_tests/test_alembic.py @@ -39,9 +39,9 @@ def test_alembic_revisions_are_in_order() -> None: last = None for migration in migrations: if last is not None: - assert ( - last.revision == migration.down_revision - ), f"{last.revision} != {migration.down_revision} for {migration.path}" + assert last.revision == migration.down_revision, ( + f"{last.revision} != {migration.down_revision} for {migration.path}" + ) last = migration last = migration diff --git a/tests/unit_tests/validator_tests/test_create_plan_entry.py b/tests/unit_tests/validator_tests/test_create_plan_entry.py index 37e4c8959..7be2af7c8 100644 --- a/tests/unit_tests/validator_tests/test_create_plan_entry.py +++ b/tests/unit_tests/validator_tests/test_create_plan_entry.py @@ -1,4 +1,4 @@ -from datetime import datetime, timezone +from datetime import UTC, datetime from uuid import uuid4 import pytest @@ -7,7 +7,7 @@ from mealie.schema.meal_plan.new_meal import CreatePlanEntry def test_create_plan_with_title(): - entry = CreatePlanEntry(date=datetime.now(timezone.utc).date(), title="Test Title") + entry = CreatePlanEntry(date=datetime.now(UTC).date(), title="Test Title") assert entry.title == "Test Title" assert entry.recipe_id is None @@ -15,7 +15,7 @@ def test_create_plan_with_title(): def test_create_plan_with_slug(): uuid = uuid4() - entry = CreatePlanEntry(date=datetime.now(timezone.utc).date(), recipe_id=uuid) + entry = CreatePlanEntry(date=datetime.now(UTC).date(), recipe_id=uuid) assert entry.recipe_id == uuid assert entry.title == "" @@ -23,4 +23,4 @@ def test_create_plan_with_slug(): def test_slug_or_title_validation(): with pytest.raises(ValueError): - CreatePlanEntry(date=datetime.now(timezone.utc).date(), slug="", title="") + CreatePlanEntry(date=datetime.now(UTC).date(), slug="", title="") From e565b919dfa96bab999f55d5f081b136d4505ceb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 16:57:35 +0100 Subject: [PATCH 09/45] fix(deps): update dependency openai to v1.59.7 (#4890) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3ed33307c..ffc87b64a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1590,13 +1590,13 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openai" -version = "1.59.6" +version = "1.59.7" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" files = [ - {file = "openai-1.59.6-py3-none-any.whl", hash = "sha256:b28ed44eee3d5ebe1a3ea045ee1b4b50fea36ecd50741aaa5ce5a5559c900cb6"}, - {file = "openai-1.59.6.tar.gz", hash = "sha256:c7670727c2f1e4473f62fea6fa51475c8bc098c9ffb47bfb9eef5be23c747934"}, + {file = "openai-1.59.7-py3-none-any.whl", hash = "sha256:cfa806556226fa96df7380ab2e29814181d56fea44738c2b0e581b462c268692"}, + {file = "openai-1.59.7.tar.gz", hash = "sha256:043603def78c00befb857df9f0a16ee76a3af5984ba40cb7ee5e2f40db4646bf"}, ] [package.dependencies] From e9892aba8988a526846271417870b0d4cacbf262 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:19:49 -0600 Subject: [PATCH 10/45] feat: Move "on hand" and "last made" to household (#4616) Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- docs/docs/overrides/api.html | 2 +- .../Recipe/RecipeDialogAddToShoppingList.vue | 10 +- .../Domain/Recipe/RecipeLastMade.vue | 35 +- .../RecipePageParts/RecipePageInfoCard.vue | 1 - .../RecipePageIngredientToolsView.vue | 37 ++- frontend/components/global/AppLoader.vue | 15 +- .../composables/recipes/use-recipe-tools.ts | 1 - frontend/composables/store/use-food-store.ts | 1 - frontend/composables/store/use-tool-store.ts | 7 +- frontend/lib/api/types/admin.ts | 2 +- frontend/lib/api/types/cookbook.ts | 2 +- frontend/lib/api/types/household.ts | 29 +- frontend/lib/api/types/meal-plan.ts | 2 +- frontend/lib/api/types/recipe.ts | 20 +- frontend/lib/api/user/households.ts | 6 + .../g/_groupSlug/recipes/tools/index.vue | 44 ++- frontend/pages/group/data/foods.vue | 68 +++- frontend/pages/group/data/recipe-actions.vue | 5 - frontend/pages/group/data/tools.vue | 57 +++- ...d3b3_add_household_to_recipe_last_made_.py | 263 +++++++++++++++ mealie/db/models/household/__init__.py | 2 + mealie/db/models/household/household.py | 17 + .../models/household/household_to_recipe.py | 60 ++++ mealie/db/models/recipe/ingredient.py | 37 ++- mealie/db/models/recipe/recipe.py | 5 + mealie/db/models/recipe/tool.py | 39 ++- mealie/repos/repository_factory.py | 16 +- mealie/repos/repository_generic.py | 10 +- mealie/repos/repository_household.py | 25 +- mealie/repos/repository_recipes.py | 148 ++++----- .../controller_household_self_service.py | 11 +- .../routes/households/controller_mealplan.py | 4 +- mealie/routes/organizers/controller_tools.py | 1 + mealie/routes/recipe/recipe_crud_routes.py | 12 +- mealie/routes/unit_and_foods/foods.py | 1 + mealie/schema/household/__init__.py | 10 + mealie/schema/household/household.py | 31 +- mealie/schema/recipe/recipe.py | 12 +- mealie/schema/recipe/recipe_ingredient.py | 18 +- mealie/schema/recipe/recipe_tool.py | 28 +- mealie/schema/response/query_filter.py | 117 ++++--- .../household_services/household_service.py | 51 ++- mealie/services/recipe/recipe_service.py | 12 +- .../scheduler/tasks/create_timeline_events.py | 7 +- pyproject.toml | 6 +- .../test_household_self_service.py | 65 ++++ .../test_recipe_cross_household.py | 55 +++- .../test_recipe_suggestions.py | 82 ++++- .../repository_tests/test_pagination.py | 103 ++++++ .../test_recipe_repository.py | 61 +++- .../backup_v2_tests/test_backup_v2.py | 307 ++++++++++-------- .../tasks/test_create_timeline_events.py | 53 ++- tests/utils/api_routes/__init__.py | 5 + 53 files changed, 1618 insertions(+), 400 deletions(-) create mode 100644 mealie/alembic/versions/2024-11-20-17.30.41_b9e516e2d3b3_add_household_to_recipe_last_made_.py create mode 100644 mealie/db/models/household/household_to_recipe.py diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index 8c7f4880d..a6f596205 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue index 789d59bd4..6f233b84f 100644 --- a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue +++ b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue @@ -204,6 +204,10 @@ export default defineComponent({ shoppingListShowAllToggled: false, }); + const userHousehold = computed(() => { + return $auth.user?.householdSlug || ""; + }); + const shoppingListChoices = computed(() => { return props.shoppingLists.filter((list) => preferences.value.viewAllLists || list.userId === $auth.user?.id); }); @@ -248,8 +252,9 @@ export default defineComponent({ } const shoppingListIngredients: ShoppingListIngredient[] = recipe.recipeIngredient.map((ing) => { + const householdsWithFood = (ing.food?.householdsWithIngredientFood || []); return { - checked: !ing.food?.onHand, + checked: !householdsWithFood.includes(userHousehold.value), ingredient: ing, disableAmount: recipe.settings?.disableAmount || false, } @@ -276,7 +281,8 @@ export default defineComponent({ } // Store the on-hand ingredients for later - if (ing.ingredient.food?.onHand) { + const householdsWithFood = (ing.ingredient.food?.householdsWithIngredientFood || []); + if (householdsWithFood.includes(userHousehold.value)) { onHandIngs.push(ing); return sections; } diff --git a/frontend/components/Domain/Recipe/RecipeLastMade.vue b/frontend/components/Domain/Recipe/RecipeLastMade.vue index d60de97b4..178db28bd 100644 --- a/frontend/components/Domain/Recipe/RecipeLastMade.vue +++ b/frontend/components/Domain/Recipe/RecipeLastMade.vue @@ -96,7 +96,12 @@ {{ $globals.icons.calendar }} - {{ $t('recipe.last-made-date', { date: value ? new Date(value).toLocaleDateString($i18n.locale) : $t("general.never") } ) }} +
+ {{ $t('recipe.last-made-date', { date: lastMade ? new Date(lastMade).toLocaleDateString($i18n.locale) : $t("general.never") } ) }} +
+
+ +
@@ -110,7 +115,7 @@