From 6e19d9f65fec5ef3df6ee8c6d8ac2b173c3cdc08 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Wed, 7 May 2025 03:10:50 +0300 Subject: [PATCH] Add new dependencies and standardize file formatting Added `paramiko`, `django-dbbackup`, `django-storages`, and `bcrypt` to the dependency list in `pyproject.toml`. Reformatted file entries in `poetry.lock` to ensure consistent alignment with style guidelines, improving readability and maintainability. --- README.md | 12 ++- evibes/settings/__init__.py | 1 + evibes/settings/base.py | 15 ++++ evibes/settings/dbbackup.py | 20 +++++ poetry.lock | 151 +++++++++++++++++++++++++++++++++++- pyproject.toml | 3 + 6 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 evibes/settings/dbbackup.py diff --git a/README.md b/README.md index a02e5c26..47e4d6c0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # eVibes + ![LOGO](core/docs/images/evibes-big.png) -eVibes is an eCommerce backend service built with Django. It’s designed for flexibility, making it ideal for various use cases and learning Django skills. The project is easy to customize, allowing for straightforward editing and extension. +eVibes is an eCommerce backend service built with Django. It’s designed for flexibility, making it ideal for various use +cases and learning Django skills. The project is easy to customize, allowing for straightforward editing and extension. ## Table of Contents @@ -54,7 +56,8 @@ eVibes is an eCommerce backend service built with Django. It’s designed for fl ### Dockerfile -Don't forget to change the `RUN sed -i 's|https://deb.debian.org/debian|https://ftp..debian.org/debian|g' /etc/apt/sources.list.d/debian.sources` +Don't forget to change the +`RUN sed -i 's|https://deb.debian.org/debian|https://ftp..debian.org/debian|g' /etc/apt/sources.list.d/debian.sources` ### Environment Variables @@ -78,6 +81,10 @@ POSTGRES_DB="evibes" POSTGRES_USER="evibes_user" POSTGRES_PASSWORD="SUPERSECRETPOSTGRESPASSWORD" +DBBACKUP_SFTP_HOST="Your SFTP backup host" +DBBACKUP_SFTP_USER="The username to use to log in to that host" +DBBACKUP_SFTP_PASS="The password to use to log in to that host" + ELASTIC_PASSWORD="SUPERSECRETELASTICPASSWORD" REDIS_PASSWORD="SUPERSECRETREDISPASSWORD" @@ -111,6 +118,7 @@ ABSTRACT_API_KEY="Haha, really? x2" ## Usage Add these lines to your hosts-file to use django-hosts functionality on localhost: + ```hosts 127.0.0.1 api.localhost 127.0.0.1 b2b.localhost diff --git a/evibes/settings/__init__.py b/evibes/settings/__init__.py index b6805ab6..2c87ce42 100644 --- a/evibes/settings/__init__.py +++ b/evibes/settings/__init__.py @@ -3,6 +3,7 @@ from .celery import * # noqa: F403 from .constance import * # noqa: F403 from .csp import * # noqa: F403 from .database import * # noqa: F403 +from .dbbackup import * # noqa: F403 from .drf import * # noqa: F403 from .elasticsearch import * # noqa: F403 from .emailing import * # noqa: F403 diff --git a/evibes/settings/base.py b/evibes/settings/base.py index 954c8ca3..851977ac 100644 --- a/evibes/settings/base.py +++ b/evibes/settings/base.py @@ -81,6 +81,7 @@ INSTALLED_APPS = [ "drf_spectacular_sidecar", "django_json_widget", "django_elasticsearch_dsl", + "dbbackup", "corsheaders", "constance.backends.database", "django_mailbox", @@ -304,3 +305,17 @@ CSRF_COOKIE_HTTPONLY = True LANGUAGE_COOKIE_HTTPONLY = True DATA_UPLOAD_MAX_NUMBER_FIELDS = 8888 + +ADMINS = [('Egor Gorbunov', 'contact@fureunoir.com')] + +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, + "dbbackup": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + } +} diff --git a/evibes/settings/dbbackup.py b/evibes/settings/dbbackup.py new file mode 100644 index 00000000..69d0cb71 --- /dev/null +++ b/evibes/settings/dbbackup.py @@ -0,0 +1,20 @@ +from evibes.settings.base import getenv + +if getenv("DBBACKUP_SFTP_HOST") and getenv("DBBACKUP_SFTP_USER") and getenv("DBBACKUP_SFTP_PASS"): + DBBACKUP_STORAGE = "storages.backends.sftpstorage.SFTPStorage" + DBBACKUP_STORAGE_OPTIONS = { + "host": getenv("DBBACKUP_SFTP_HOST"), + "root_path": "/db_backups/", + "params": { + "username": getenv("DBBACKUP_SFTP_USER"), + "password": getenv("DBBACKUP_SFTP_PASS"), + "allow_agent": False, + "look_for_keys": False, + }, + "interactive": False, + "file_mode": 0o600, + "dir_mode": 0o700, + } +else: + DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage" + DBBACKUP_STORAGE_OPTIONS = {"location": "/app/db_backups/"} diff --git a/poetry.lock b/poetry.lock index e1468dce..ae5722f8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -206,6 +206,70 @@ files = [ [package.extras] dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] +[[package]] +name = "bcrypt" +version = "4.3.0" +description = "Modern password hashing for your software and your servers" +optional = false +python-versions = ">=3.8" +files = [ + { file = "bcrypt-4.3.0-cp313-cp313t-macosx_10_12_universal2.whl", hash = "sha256:f01e060f14b6b57bbb72fc5b4a83ac21c443c9a2ee708e04a10e9192f90a6281" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5eeac541cefd0bb887a371ef73c62c3cd78535e4887b310626036a7c0a817bb" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59e1aa0e2cd871b08ca146ed08445038f42ff75968c7ae50d2fdd7860ade2180" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:0042b2e342e9ae3d2ed22727c1262f76cc4f345683b5c1715f0250cf4277294f" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74a8d21a09f5e025a9a23e7c0fd2c7fe8e7503e4d356c0a2c1486ba010619f09" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:0142b2cb84a009f8452c8c5a33ace5e3dfec4159e7735f5afe9a4d50a8ea722d" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_aarch64.whl", hash = "sha256:12fa6ce40cde3f0b899729dbd7d5e8811cb892d31b6f7d0334a1f37748b789fd" }, + { file = "bcrypt-4.3.0-cp313-cp313t-manylinux_2_34_x86_64.whl", hash = "sha256:5bd3cca1f2aa5dbcf39e2aa13dd094ea181f48959e1071265de49cc2b82525af" }, + { file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:335a420cfd63fc5bc27308e929bee231c15c85cc4c496610ffb17923abf7f231" }, + { file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:0e30e5e67aed0187a1764911af023043b4542e70a7461ad20e837e94d23e1d6c" }, + { file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b8d62290ebefd49ee0b3ce7500f5dbdcf13b81402c05f6dafab9a1e1b27212f" }, + { file = "bcrypt-4.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef6630e0ec01376f59a006dc72918b1bf436c3b571b80fa1968d775fa02fe7d" }, + { file = "bcrypt-4.3.0-cp313-cp313t-win32.whl", hash = "sha256:7a4be4cbf241afee43f1c3969b9103a41b40bcb3a3f467ab19f891d9bc4642e4" }, + { file = "bcrypt-4.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c1949bf259a388863ced887c7861da1df681cb2388645766c89fdfd9004c669" }, + { file = "bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb" }, + { file = "bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d" }, + { file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f" }, + { file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732" }, + { file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef" }, + { file = "bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304" }, + { file = "bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51" }, + { file = "bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62" }, + { file = "bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe" }, + { file = "bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0" }, + { file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f" }, + { file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23" }, + { file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe" }, + { file = "bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505" }, + { file = "bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a" }, + { file = "bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b" }, + { file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c950d682f0952bafcceaf709761da0a32a942272fad381081b51096ffa46cea1" }, + { file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:107d53b5c67e0bbc3f03ebf5b030e0403d24dda980f8e244795335ba7b4a027d" }, + { file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b693dbb82b3c27a1604a3dff5bfc5418a7e6a781bb795288141e5f80cf3a3492" }, + { file = "bcrypt-4.3.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:b6354d3760fcd31994a14c89659dee887f1351a06e5dac3c1142307172a79f90" }, + { file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a" }, + { file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce" }, + { file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8" }, + { file = "bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938" }, + { file = "bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18" }, +] + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + [[package]] name = "beautifulsoup4" version = "4.13.4" @@ -851,6 +915,21 @@ files = [ [package.dependencies] Django = ">=3.2" +[[package]] +name = "django-dbbackup" +version = "4.2.1" +description = "Management commands to help backup and restore a project database and media." +optional = false +python-versions = ">=3.7" +files = [ + { file = "django_dbbackup-4.2.1-py3-none-any.whl", hash = "sha256:b23265600ead0780ca781b1b4b594949aaa8a20d74f08701f91ee9d7eb1f08cd" }, + { file = "django_dbbackup-4.2.1.tar.gz", hash = "sha256:157a2ec10d482345cd75092e510ac40d6e2ee6084604a1d17abe178c2f06bc69" }, +] + +[package.dependencies] +django = ">=3.2" +pytz = "*" + [[package]] name = "django-elasticsearch-dsl" version = "8.0" @@ -1071,6 +1150,29 @@ redis = ">=3,<4.0.0 || >4.0.0,<4.0.1 || >4.0.1" [package.extras] hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] +[[package]] +name = "django-storages" +version = "1.14.6" +description = "Support for many storage backends in Django" +optional = false +python-versions = ">=3.7" +files = [ + { file = "django_storages-1.14.6-py3-none-any.whl", hash = "sha256:11b7b6200e1cb5ffcd9962bd3673a39c7d6a6109e8096f0e03d46fab3d3aabd9" }, + { file = "django_storages-1.14.6.tar.gz", hash = "sha256:7a25ce8f4214f69ac9c7ce87e2603887f7ae99326c316bc8d2d75375e09341c9" }, +] + +[package.dependencies] +Django = ">=3.2" + +[package.extras] +azure = ["azure-core (>=1.13)", "azure-storage-blob (>=12)"] +boto3 = ["boto3 (>=1.4.4)"] +dropbox = ["dropbox (>=7.2.1)"] +google = ["google-cloud-storage (>=1.36.1)"] +libcloud = ["apache-libcloud"] +s3 = ["boto3 (>=1.4.4)"] +sftp = ["paramiko (>=1.15)"] + [[package]] name = "django-timezone-field" version = "7.1" @@ -2460,6 +2562,27 @@ files = [ { file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e" }, ] +[[package]] +name = "paramiko" +version = "3.5.1" +description = "SSH2 protocol library" +optional = false +python-versions = ">=3.6" +files = [ + { file = "paramiko-3.5.1-py3-none-any.whl", hash = "sha256:43b9a0501fc2b5e70680388d9346cf252cfb7d00b0667c39e80eb43a408b8f61" }, + { file = "paramiko-3.5.1.tar.gz", hash = "sha256:b2c665bc45b2b215bd7d7f039901b14b067da00f3a11e6640995fd58f2664822" }, +] + +[package.dependencies] +bcrypt = ">=3.2" +cryptography = ">=3.3" +pynacl = ">=1.5" + +[package.extras] +all = ["gssapi (>=1.4.1)", "invoke (>=2.0)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] +gssapi = ["gssapi (>=1.4.1)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] +invoke = ["invoke (>=2.0)"] + [[package]] name = "parso" version = "0.8.4" @@ -2938,6 +3061,32 @@ pyyaml = "*" [package.extras] extra = ["pygments (>=2.19.1)"] +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +optional = false +python-versions = ">=3.6" +files = [ + { file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1" }, + { file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92" }, + { file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394" }, + { file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d" }, + { file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858" }, + { file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b" }, + { file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff" }, + { file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543" }, + { file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93" }, + { file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba" }, +] + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + [[package]] name = "python-crontab" version = "3.2.0" @@ -3888,4 +4037,4 @@ worker = ["celery", "django-celery-beat"] [metadata] lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "e67ba20e47d15b3ddbe6bd24249b07fca49ad330ffdf3dfc12ca75260f5ddad1" +content-hash = "4079e4ea32df5c36446f1a1bc151c2f6c17afac4fc686d188370d643c2a56e6d" diff --git a/pyproject.toml b/pyproject.toml index fe5c6142..1b2af5b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,7 @@ psycopg2 = "2.9.10" polib = "1.2.0" openai = { version = "1.77.0", optional = true } swapper = "1.4.0" +paramiko = "3.5.1" filetype = "1.2.0" colorlog = "6.9.0" pymdown-extensions = "10.15" @@ -40,6 +41,8 @@ django-ratelimit = "4.1.0" django-hosts = "6.0" django-mptt = "0.17.0" django-filter = "25.1" +django-dbbackup = "4.2.1" +django-storages = "1.14.6" django-constance = "4.3.2" django-daisy = "1.0.23" django-cacheops = "7.2"