From d39f9a23f3217ef36141e064ba2be8cf5ba9aa09 Mon Sep 17 00:00:00 2001 From: A'zamov Samandar Date: Mon, 21 Apr 2025 18:42:21 +0500 Subject: [PATCH] Docker compose konfiguratsiyasini yangilandi va xizmatlar uchun yangi buyruqlar qo'shildi. --- Makefile | 33 +- docker-compose.yml | 84 +- notification/docker-compose.yml | 12 + order/.cruft.json | 28 + order/.dockerignore | 2 + order/.env.example | 63 + order/.flake8 | 3 + order/.gitignore | 158 + order/README.MD | 2 + order/config/__init__.py | 3 + order/config/asgi.py | 23 + order/config/celery.py | 16 + order/config/conf/__init__.py | 12 + order/config/conf/apps.py | 19 + order/config/conf/cache.py | 26 + order/config/conf/celery.py | 7 + order/config/conf/channels.py | 8 + order/config/conf/ckeditor.py | 147 + order/config/conf/cron.py | 0 order/config/conf/jwt.py | 36 + order/config/conf/logs.py | 29 + order/config/conf/modules.py | 1 + order/config/conf/navigation.py | 31 + order/config/conf/rest_framework.py | 9 + order/config/conf/spectacular.py | 31 + order/config/conf/storage.py | 23 + order/config/conf/unfold.py | 41 + order/config/env.py | 28 + order/config/settings/__init__.py | 0 order/config/settings/common.py | 172 + order/config/settings/local.py | 11 + order/config/settings/production.py | 6 + order/config/urls.py | 55 + order/config/wsgi.py | 8 + order/core/__init__.py | 0 order/core/apps/__init__.py | 0 order/core/services/__init__.py | 0 order/core/utils/__init__.py | 3 + order/core/utils/cache.py | 18 + order/core/utils/console.py | 79 + order/core/utils/core.py | 6 + order/core/utils/storage.py | 33 + order/docker-compose.yml | 53 + order/docker/Dockerfile.nginx | 3 + order/docker/Dockerfile.web | 9 + order/jst.json | 8 + order/manage.py | 24 + order/pyproject.toml | 21 + order/requirements.txt | 45 + order/resources/.gitignore | 1 + order/resources/layout/.flake8 | 3 + order/resources/layout/Dockerfile.alpine | 13 + order/resources/layout/Dockerfile.nginx | 3 + order/resources/layout/mypy.ini | 5 + order/resources/layout/nginx.conf | 54 + order/resources/locale/.gitkeep | 0 .../resources/locale/en/LC_MESSAGES/django.po | 49 + .../resources/locale/ru/LC_MESSAGES/django.po | 51 + .../resources/locale/uz/LC_MESSAGES/django.po | 55 + order/resources/logs/.gitignore | 2 + order/resources/media/.gitignore | 2 + order/resources/scripts/backup.sh | 5 + order/resources/scripts/entrypoint-server.sh | 11 + order/resources/scripts/entrypoint.sh | 11 + order/resources/static/css/app.css | 0 order/resources/static/css/error.css | 109 + order/resources/static/css/input.css | 3 + order/resources/static/css/jazzmin.css | 5 + order/resources/static/css/output.css | 772 ++ order/resources/static/images/logo.png | Bin 0 -> 39362 bytes order/resources/static/js/alpine.js | 9 + order/resources/static/js/app.js | 1 + order/resources/static/js/counter.js | 3 + order/resources/static/js/customer.js | 49 + order/resources/static/js/vite-refresh.js | 9 + .../static/vite/assets/appCss-w40geAFS.js | 0 .../static/vite/assets/appJs-YH6iAcjX.js | 6 + .../static/vite/assets/outCss-r8J2MRAR.css | 1 + order/resources/static/vite/manifest.json | 17 + order/resources/templates/400.html | 148 + order/resources/templates/401.html | 147 + order/resources/templates/403.html | 145 + order/resources/templates/404.html | 147 + order/resources/templates/405.html | 145 + order/resources/templates/408.html | 145 + order/resources/templates/500.html | 145 + order/resources/templates/502.html | 145 + order/resources/templates/503.html | 145 + order/resources/templates/504.html | 145 + order/resources/templates/admin/index.html | 40 + .../templates/registration/login.html | 15 + order/resources/templates/user/home.html | 48 + payment/config/settings.py | 3 +- payment/docker-compose.yml | 26 + payment/entrypoint.sh | 2 +- .../staticfiles/admin/css/autocomplete.css | 279 + payment/staticfiles/admin/css/base.css | 1179 ++ payment/staticfiles/admin/css/changelists.css | 343 + payment/staticfiles/admin/css/dark_mode.css | 130 + payment/staticfiles/admin/css/dashboard.css | 29 + payment/staticfiles/admin/css/forms.css | 512 + payment/staticfiles/admin/css/login.css | 61 + payment/staticfiles/admin/css/nav_sidebar.css | 150 + payment/staticfiles/admin/css/responsive.css | 967 ++ .../staticfiles/admin/css/responsive_rtl.css | 111 + payment/staticfiles/admin/css/rtl.css | 291 + .../admin/css/unusable_password_field.css | 19 + .../css/vendor/select2/LICENSE-SELECT2.md | 21 + .../admin/css/vendor/select2/select2.css | 481 + .../admin/css/vendor/select2/select2.min.css | 1 + payment/staticfiles/admin/css/widgets.css | 593 + payment/staticfiles/admin/img/LICENSE | 20 + payment/staticfiles/admin/img/README.txt | 7 + .../staticfiles/admin/img/calendar-icons.svg | 63 + .../admin/img/gis/move_vertex_off.svg | 1 + .../admin/img/gis/move_vertex_on.svg | 1 + .../staticfiles/admin/img/icon-addlink.svg | 3 + payment/staticfiles/admin/img/icon-alert.svg | 3 + .../staticfiles/admin/img/icon-calendar.svg | 9 + .../staticfiles/admin/img/icon-changelink.svg | 3 + payment/staticfiles/admin/img/icon-clock.svg | 9 + .../staticfiles/admin/img/icon-deletelink.svg | 3 + .../staticfiles/admin/img/icon-hidelink.svg | 3 + payment/staticfiles/admin/img/icon-no.svg | 3 + .../admin/img/icon-unknown-alt.svg | 3 + .../staticfiles/admin/img/icon-unknown.svg | 3 + .../staticfiles/admin/img/icon-viewlink.svg | 3 + payment/staticfiles/admin/img/icon-yes.svg | 3 + .../staticfiles/admin/img/inline-delete.svg | 3 + payment/staticfiles/admin/img/search.svg | 3 + .../staticfiles/admin/img/selector-icons.svg | 34 + .../staticfiles/admin/img/sorting-icons.svg | 19 + payment/staticfiles/admin/img/tooltag-add.svg | 3 + .../admin/img/tooltag-arrowright.svg | 3 + payment/staticfiles/admin/js/SelectBox.js | 116 + payment/staticfiles/admin/js/SelectFilter2.js | 286 + payment/staticfiles/admin/js/actions.js | 204 + .../admin/js/admin/DateTimeShortcuts.js | 408 + .../admin/js/admin/RelatedObjectLookups.js | 240 + payment/staticfiles/admin/js/autocomplete.js | 33 + payment/staticfiles/admin/js/calendar.js | 239 + payment/staticfiles/admin/js/cancel.js | 29 + payment/staticfiles/admin/js/change_form.js | 16 + payment/staticfiles/admin/js/core.js | 184 + payment/staticfiles/admin/js/filters.js | 30 + payment/staticfiles/admin/js/inlines.js | 359 + payment/staticfiles/admin/js/jquery.init.js | 8 + payment/staticfiles/admin/js/nav_sidebar.js | 79 + .../staticfiles/admin/js/popup_response.js | 15 + payment/staticfiles/admin/js/prepopulate.js | 43 + .../staticfiles/admin/js/prepopulate_init.js | 15 + payment/staticfiles/admin/js/theme.js | 51 + .../admin/js/unusable_password_field.js | 29 + payment/staticfiles/admin/js/urlify.js | 169 + .../admin/js/vendor/jquery/LICENSE.txt | 20 + .../admin/js/vendor/jquery/jquery.js | 10716 ++++++++++++++++ .../admin/js/vendor/jquery/jquery.min.js | 2 + .../admin/js/vendor/select2/LICENSE.md | 21 + .../admin/js/vendor/select2/i18n/af.js | 3 + .../admin/js/vendor/select2/i18n/ar.js | 3 + .../admin/js/vendor/select2/i18n/az.js | 3 + .../admin/js/vendor/select2/i18n/bg.js | 3 + .../admin/js/vendor/select2/i18n/bn.js | 3 + .../admin/js/vendor/select2/i18n/bs.js | 3 + .../admin/js/vendor/select2/i18n/ca.js | 3 + .../admin/js/vendor/select2/i18n/cs.js | 3 + .../admin/js/vendor/select2/i18n/da.js | 3 + .../admin/js/vendor/select2/i18n/de.js | 3 + .../admin/js/vendor/select2/i18n/dsb.js | 3 + .../admin/js/vendor/select2/i18n/el.js | 3 + .../admin/js/vendor/select2/i18n/en.js | 3 + .../admin/js/vendor/select2/i18n/es.js | 3 + .../admin/js/vendor/select2/i18n/et.js | 3 + .../admin/js/vendor/select2/i18n/eu.js | 3 + .../admin/js/vendor/select2/i18n/fa.js | 3 + .../admin/js/vendor/select2/i18n/fi.js | 3 + .../admin/js/vendor/select2/i18n/fr.js | 3 + .../admin/js/vendor/select2/i18n/gl.js | 3 + .../admin/js/vendor/select2/i18n/he.js | 3 + .../admin/js/vendor/select2/i18n/hi.js | 3 + .../admin/js/vendor/select2/i18n/hr.js | 3 + .../admin/js/vendor/select2/i18n/hsb.js | 3 + .../admin/js/vendor/select2/i18n/hu.js | 3 + .../admin/js/vendor/select2/i18n/hy.js | 3 + .../admin/js/vendor/select2/i18n/id.js | 3 + .../admin/js/vendor/select2/i18n/is.js | 3 + .../admin/js/vendor/select2/i18n/it.js | 3 + .../admin/js/vendor/select2/i18n/ja.js | 3 + .../admin/js/vendor/select2/i18n/ka.js | 3 + .../admin/js/vendor/select2/i18n/km.js | 3 + .../admin/js/vendor/select2/i18n/ko.js | 3 + .../admin/js/vendor/select2/i18n/lt.js | 3 + .../admin/js/vendor/select2/i18n/lv.js | 3 + .../admin/js/vendor/select2/i18n/mk.js | 3 + .../admin/js/vendor/select2/i18n/ms.js | 3 + .../admin/js/vendor/select2/i18n/nb.js | 3 + .../admin/js/vendor/select2/i18n/ne.js | 3 + .../admin/js/vendor/select2/i18n/nl.js | 3 + .../admin/js/vendor/select2/i18n/pl.js | 3 + .../admin/js/vendor/select2/i18n/ps.js | 3 + .../admin/js/vendor/select2/i18n/pt-BR.js | 3 + .../admin/js/vendor/select2/i18n/pt.js | 3 + .../admin/js/vendor/select2/i18n/ro.js | 3 + .../admin/js/vendor/select2/i18n/ru.js | 3 + .../admin/js/vendor/select2/i18n/sk.js | 3 + .../admin/js/vendor/select2/i18n/sl.js | 3 + .../admin/js/vendor/select2/i18n/sq.js | 3 + .../admin/js/vendor/select2/i18n/sr-Cyrl.js | 3 + .../admin/js/vendor/select2/i18n/sr.js | 3 + .../admin/js/vendor/select2/i18n/sv.js | 3 + .../admin/js/vendor/select2/i18n/th.js | 3 + .../admin/js/vendor/select2/i18n/tk.js | 3 + .../admin/js/vendor/select2/i18n/tr.js | 3 + .../admin/js/vendor/select2/i18n/uk.js | 3 + .../admin/js/vendor/select2/i18n/vi.js | 3 + .../admin/js/vendor/select2/i18n/zh-CN.js | 3 + .../admin/js/vendor/select2/i18n/zh-TW.js | 3 + .../admin/js/vendor/select2/select2.full.js | 6820 ++++++++++ .../js/vendor/select2/select2.full.min.js | 2 + .../admin/js/vendor/xregexp/LICENSE.txt | 21 + .../admin/js/vendor/xregexp/xregexp.js | 6126 +++++++++ .../admin/js/vendor/xregexp/xregexp.min.js | 17 + template/docker-compose.yml | 19 + template/entrypoint.sh | 2 +- user/core/apps/accounts/urls.py | 3 +- user/core/apps/accounts/views/__init__.py | 1 + user/core/apps/accounts/views/user.py | 9 + user/docker-compose.yml | 36 +- 228 files changed, 36071 insertions(+), 115 deletions(-) create mode 100644 notification/docker-compose.yml create mode 100644 order/.cruft.json create mode 100644 order/.dockerignore create mode 100644 order/.env.example create mode 100644 order/.flake8 create mode 100644 order/.gitignore create mode 100644 order/README.MD create mode 100644 order/config/__init__.py create mode 100644 order/config/asgi.py create mode 100644 order/config/celery.py create mode 100644 order/config/conf/__init__.py create mode 100644 order/config/conf/apps.py create mode 100644 order/config/conf/cache.py create mode 100644 order/config/conf/celery.py create mode 100644 order/config/conf/channels.py create mode 100644 order/config/conf/ckeditor.py create mode 100644 order/config/conf/cron.py create mode 100644 order/config/conf/jwt.py create mode 100644 order/config/conf/logs.py create mode 100644 order/config/conf/modules.py create mode 100644 order/config/conf/navigation.py create mode 100644 order/config/conf/rest_framework.py create mode 100644 order/config/conf/spectacular.py create mode 100644 order/config/conf/storage.py create mode 100644 order/config/conf/unfold.py create mode 100644 order/config/env.py create mode 100644 order/config/settings/__init__.py create mode 100644 order/config/settings/common.py create mode 100644 order/config/settings/local.py create mode 100644 order/config/settings/production.py create mode 100644 order/config/urls.py create mode 100644 order/config/wsgi.py create mode 100644 order/core/__init__.py create mode 100644 order/core/apps/__init__.py create mode 100644 order/core/services/__init__.py create mode 100644 order/core/utils/__init__.py create mode 100644 order/core/utils/cache.py create mode 100644 order/core/utils/console.py create mode 100644 order/core/utils/core.py create mode 100644 order/core/utils/storage.py create mode 100644 order/docker-compose.yml create mode 100644 order/docker/Dockerfile.nginx create mode 100644 order/docker/Dockerfile.web create mode 100644 order/jst.json create mode 100644 order/manage.py create mode 100644 order/pyproject.toml create mode 100644 order/requirements.txt create mode 100644 order/resources/.gitignore create mode 100644 order/resources/layout/.flake8 create mode 100644 order/resources/layout/Dockerfile.alpine create mode 100644 order/resources/layout/Dockerfile.nginx create mode 100644 order/resources/layout/mypy.ini create mode 100644 order/resources/layout/nginx.conf create mode 100644 order/resources/locale/.gitkeep create mode 100644 order/resources/locale/en/LC_MESSAGES/django.po create mode 100644 order/resources/locale/ru/LC_MESSAGES/django.po create mode 100644 order/resources/locale/uz/LC_MESSAGES/django.po create mode 100644 order/resources/logs/.gitignore create mode 100644 order/resources/media/.gitignore create mode 100644 order/resources/scripts/backup.sh create mode 100644 order/resources/scripts/entrypoint-server.sh create mode 100644 order/resources/scripts/entrypoint.sh create mode 100644 order/resources/static/css/app.css create mode 100644 order/resources/static/css/error.css create mode 100644 order/resources/static/css/input.css create mode 100644 order/resources/static/css/jazzmin.css create mode 100644 order/resources/static/css/output.css create mode 100644 order/resources/static/images/logo.png create mode 100644 order/resources/static/js/alpine.js create mode 100644 order/resources/static/js/app.js create mode 100644 order/resources/static/js/counter.js create mode 100644 order/resources/static/js/customer.js create mode 100644 order/resources/static/js/vite-refresh.js create mode 100644 order/resources/static/vite/assets/appCss-w40geAFS.js create mode 100644 order/resources/static/vite/assets/appJs-YH6iAcjX.js create mode 100644 order/resources/static/vite/assets/outCss-r8J2MRAR.css create mode 100644 order/resources/static/vite/manifest.json create mode 100644 order/resources/templates/400.html create mode 100644 order/resources/templates/401.html create mode 100644 order/resources/templates/403.html create mode 100644 order/resources/templates/404.html create mode 100644 order/resources/templates/405.html create mode 100644 order/resources/templates/408.html create mode 100644 order/resources/templates/500.html create mode 100644 order/resources/templates/502.html create mode 100644 order/resources/templates/503.html create mode 100644 order/resources/templates/504.html create mode 100644 order/resources/templates/admin/index.html create mode 100644 order/resources/templates/registration/login.html create mode 100644 order/resources/templates/user/home.html create mode 100644 payment/docker-compose.yml create mode 100644 payment/staticfiles/admin/css/autocomplete.css create mode 100644 payment/staticfiles/admin/css/base.css create mode 100644 payment/staticfiles/admin/css/changelists.css create mode 100644 payment/staticfiles/admin/css/dark_mode.css create mode 100644 payment/staticfiles/admin/css/dashboard.css create mode 100644 payment/staticfiles/admin/css/forms.css create mode 100644 payment/staticfiles/admin/css/login.css create mode 100644 payment/staticfiles/admin/css/nav_sidebar.css create mode 100644 payment/staticfiles/admin/css/responsive.css create mode 100644 payment/staticfiles/admin/css/responsive_rtl.css create mode 100644 payment/staticfiles/admin/css/rtl.css create mode 100644 payment/staticfiles/admin/css/unusable_password_field.css create mode 100644 payment/staticfiles/admin/css/vendor/select2/LICENSE-SELECT2.md create mode 100644 payment/staticfiles/admin/css/vendor/select2/select2.css create mode 100644 payment/staticfiles/admin/css/vendor/select2/select2.min.css create mode 100644 payment/staticfiles/admin/css/widgets.css create mode 100644 payment/staticfiles/admin/img/LICENSE create mode 100644 payment/staticfiles/admin/img/README.txt create mode 100644 payment/staticfiles/admin/img/calendar-icons.svg create mode 100644 payment/staticfiles/admin/img/gis/move_vertex_off.svg create mode 100644 payment/staticfiles/admin/img/gis/move_vertex_on.svg create mode 100644 payment/staticfiles/admin/img/icon-addlink.svg create mode 100644 payment/staticfiles/admin/img/icon-alert.svg create mode 100644 payment/staticfiles/admin/img/icon-calendar.svg create mode 100644 payment/staticfiles/admin/img/icon-changelink.svg create mode 100644 payment/staticfiles/admin/img/icon-clock.svg create mode 100644 payment/staticfiles/admin/img/icon-deletelink.svg create mode 100644 payment/staticfiles/admin/img/icon-hidelink.svg create mode 100644 payment/staticfiles/admin/img/icon-no.svg create mode 100644 payment/staticfiles/admin/img/icon-unknown-alt.svg create mode 100644 payment/staticfiles/admin/img/icon-unknown.svg create mode 100644 payment/staticfiles/admin/img/icon-viewlink.svg create mode 100644 payment/staticfiles/admin/img/icon-yes.svg create mode 100644 payment/staticfiles/admin/img/inline-delete.svg create mode 100644 payment/staticfiles/admin/img/search.svg create mode 100644 payment/staticfiles/admin/img/selector-icons.svg create mode 100644 payment/staticfiles/admin/img/sorting-icons.svg create mode 100644 payment/staticfiles/admin/img/tooltag-add.svg create mode 100644 payment/staticfiles/admin/img/tooltag-arrowright.svg create mode 100644 payment/staticfiles/admin/js/SelectBox.js create mode 100644 payment/staticfiles/admin/js/SelectFilter2.js create mode 100644 payment/staticfiles/admin/js/actions.js create mode 100644 payment/staticfiles/admin/js/admin/DateTimeShortcuts.js create mode 100644 payment/staticfiles/admin/js/admin/RelatedObjectLookups.js create mode 100644 payment/staticfiles/admin/js/autocomplete.js create mode 100644 payment/staticfiles/admin/js/calendar.js create mode 100644 payment/staticfiles/admin/js/cancel.js create mode 100644 payment/staticfiles/admin/js/change_form.js create mode 100644 payment/staticfiles/admin/js/core.js create mode 100644 payment/staticfiles/admin/js/filters.js create mode 100644 payment/staticfiles/admin/js/inlines.js create mode 100644 payment/staticfiles/admin/js/jquery.init.js create mode 100644 payment/staticfiles/admin/js/nav_sidebar.js create mode 100644 payment/staticfiles/admin/js/popup_response.js create mode 100644 payment/staticfiles/admin/js/prepopulate.js create mode 100644 payment/staticfiles/admin/js/prepopulate_init.js create mode 100644 payment/staticfiles/admin/js/theme.js create mode 100644 payment/staticfiles/admin/js/unusable_password_field.js create mode 100644 payment/staticfiles/admin/js/urlify.js create mode 100644 payment/staticfiles/admin/js/vendor/jquery/LICENSE.txt create mode 100644 payment/staticfiles/admin/js/vendor/jquery/jquery.js create mode 100644 payment/staticfiles/admin/js/vendor/jquery/jquery.min.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/LICENSE.md create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/af.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ar.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/az.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/bg.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/bn.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/bs.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ca.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/cs.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/da.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/de.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/dsb.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/el.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/en.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/es.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/et.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/eu.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/fa.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/fi.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/fr.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/gl.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/he.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/hi.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/hr.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/hsb.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/hu.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/hy.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/id.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/is.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/it.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ja.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ka.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/km.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ko.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/lt.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/lv.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/mk.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ms.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/nb.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ne.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/nl.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/pl.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ps.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/pt-BR.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/pt.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ro.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/ru.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/sk.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/sl.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/sq.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/sr-Cyrl.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/sr.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/sv.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/th.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/tk.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/tr.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/uk.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/vi.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/zh-CN.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/i18n/zh-TW.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/select2.full.js create mode 100644 payment/staticfiles/admin/js/vendor/select2/select2.full.min.js create mode 100644 payment/staticfiles/admin/js/vendor/xregexp/LICENSE.txt create mode 100644 payment/staticfiles/admin/js/vendor/xregexp/xregexp.js create mode 100644 payment/staticfiles/admin/js/vendor/xregexp/xregexp.min.js create mode 100644 template/docker-compose.yml create mode 100644 user/core/apps/accounts/views/user.py diff --git a/Makefile b/Makefile index d71cf8d..20782c0 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,25 @@ -up-user: - docker compose --profile user up -d -down-user: - docker compose --profile user down -up-payment: - docker compose --profile payment up -d -down-payment: - docker compose --profile payment down +SERVICES ?= -f order/docker-compose.yml -f user/docker-compose.yml -f payment/docker-compose.yml -f notification/docker-compose.yml +NAME ?= lamenu + + +logs: + docker compose -f $(app)/docker-compose.yml logs -f $(cn) + +sh: + docker compose -f $(app)/docker-compose.yml exec $(cn) sh + +up: + docker compose -f docker-compose.yml up -d + docker compose -f $(app)/docker-compose.yml up -d + +build: + docker compose -f $(app)/docker-compose.yml build + +down: + docker compose -f $(app)/docker-compose.yml down + +up-all: + docker compose -p $(NAME) $(SERVICES) up -d + down-all: - docker compose --profile payment --profile user --profile notification down \ No newline at end of file + docker compose -$(NAME) $(SERVICES) down \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index fe7691e..2076cc1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,6 @@ networks: lamenu: + name: lamenu driver: bridge volumes: @@ -22,88 +23,6 @@ services: - "/var/run/docker.sock:/var/run/docker.sock:ro" networks: - lamenu - user-nginx: - labels: - - "traefik.enable=true" - - "traefik.http.routers.user.rule=PathPrefix(`/user`)" - - "traefik.http.routers.user.entrypoints=web" - - "traefik.http.services.user.loadbalancer.server.port=80" - - "traefik.http.middlewares.user-strip-prefix.stripPrefix.prefixes=/user" - - "traefik.http.routers.user.middlewares=user-strip-prefix" - networks: - - lamenu - volumes: - - ./user/resources/layout/nginx.conf:/etc/nginx/nginx.conf - - ./user/resources/:/usr/share/nginx/html/resources/ - build: - context: ./user - dockerfile: ./docker/Dockerfile.nginx - depends_on: - - user - profiles: - - user - user: - networks: - - lamenu - build: - context: ./user - dockerfile: ./docker/Dockerfile.web - restart: always - command: ${user_COMMAND:-sh ./resources/scripts/entrypoint.sh} - environment: - - PYTHONPYCACHEPREFIX=/var/cache/pycache - - JWT_KEY=${JWT_KEY} - volumes: - - ./user:/code - - pycache:/var/cache/pycache - depends_on: - - user-db - - redis - profiles: - - user - user-db: - networks: - - lamenu - image: postgres:16 - restart: always - environment: - POSTGRES_DB: django - POSTGRES_USER: postgres - POSTGRES_PASSWORD: '2309' - volumes: - - pg_data:/var/lib/postgresql/data - profiles: - - user - - payment: - labels: - - "traefik.enable=true" - - "traefik.http.routers.payment.rule=PathPrefix(`/payment`)" - - "traefik.http.routers.payment.entrypoints=web" - - "traefik.http.services.payment.loadbalancer.server.port=8000" - networks: - - lamenu - build: - context: ./payment - dockerfile: ./Dockerfile - restart: always - environment: - - JWT_KEY=${JWT_KEY} - volumes: - - ./payment:/code - - pycache:/var/cache/pycache - profiles: - - payment - - notification: - build: - context: ./notification - dockerfile: Dockerfile - networks: - - lamenu - profiles: - - notification - redis: networks: - lamenu @@ -111,7 +30,6 @@ services: image: redis ports: - 6379:6379 - rabbitmq: image: rabbitmq:management networks: diff --git a/notification/docker-compose.yml b/notification/docker-compose.yml new file mode 100644 index 0000000..4ca2736 --- /dev/null +++ b/notification/docker-compose.yml @@ -0,0 +1,12 @@ +networks: + lamenu: + external: true + name: lamenu + +services: + notification: + build: + context: . + dockerfile: Dockerfile + networks: + - lamenu diff --git a/order/.cruft.json b/order/.cruft.json new file mode 100644 index 0000000..a52d028 --- /dev/null +++ b/order/.cruft.json @@ -0,0 +1,28 @@ +{ + "template": "https://github.com/JscorpTech/django", + "commit": "d8682a7685597c2cf088da2f240b78a7a71e91ec", + "checkout": null, + "context": { + "cookiecutter": { + "cacheops": true, + "silk": true, + "storage": true, + "rosetta": false, + "channels": true, + "ckeditor": true, + "modeltranslation": true, + "parler": false, + "project_name": "order", + "settings_module": "config.settings.local", + "runner": "wsgi", + "script": "entrypoint.sh", + "key": "key", + "port": "8081", + "phone": "998888112309", + "password": "2309", + "max_line_length": "120", + "project_slug": "order" + } + }, + "directory": null +} \ No newline at end of file diff --git a/order/.dockerignore b/order/.dockerignore new file mode 100644 index 0000000..fd148e5 --- /dev/null +++ b/order/.dockerignore @@ -0,0 +1,2 @@ +venv/ +resources/staticfiles/ \ No newline at end of file diff --git a/order/.env.example b/order/.env.example new file mode 100644 index 0000000..753f720 --- /dev/null +++ b/order/.env.example @@ -0,0 +1,63 @@ +# Django configs +DJANGO_SECRET_KEY=key +DEBUG=True +DJANGO_SETTINGS_MODULE=config.settings.local +COMMAND=sh ./resources/scripts/entrypoint.sh +PORT=8081 +#! debug | prod +PROJECT_ENV=debug +PROTOCOL_HTTPS=False + +# Databse configs +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases +DB_ENGINE=django.db.backends.postgresql_psycopg2 +DB_NAME=django +DB_USER=postgres +DB_PASSWORD=2309 +DB_HOST=db +DB_PORT=5432 + +# Cache +CACHE_BACKEND=django.core.cache.backends.redis.RedisCache +REDIS_URL=redis://redis:6379 + + +CACHE_ENABLED=False + +CACHE_TIMEOUT=120 + +# Vite settings +VITE_LIVE=False +VITE_PORT=5173 +VITE_HOST=127.0.0.1 + +# Sms service +SMS_API_URL=https://notify.eskiz.uz/api +SMS_LOGIN=admin@gmail.com +SMS_PASSWORD=key + +# Addition + +ALLOWED_HOSTS=127.0.0.1,web +CSRF_TRUSTED_ORIGINS=http://127.0.0.1:8081 + + +OTP_MODULE=core.services.otp +OTP_SERVICE=EskizService + + +# Storage +STORAGE_ID=id +STORAGE_KEY=key +STORAGE_URL=example.com + +#! MINIO | AWS | FILE +STORAGE_DEFAULT=FILE + +#! MINIO | AWS | STATIC +STORAGE_STATIC=STATIC + +STORAGE_BUCKET_MEDIA=name +STORAGE_BUCKET_STATIC=name +STORAGE_PATH=127.0.0.1:8081/bucket/ +STORAGE_PROTOCOL=http: diff --git a/order/.flake8 b/order/.flake8 new file mode 100644 index 0000000..95f57f4 --- /dev/null +++ b/order/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 120 +ignore = E701, E704, W503 diff --git a/order/.gitignore b/order/.gitignore new file mode 100644 index 0000000..e46f1af --- /dev/null +++ b/order/.gitignore @@ -0,0 +1,158 @@ +node_modules + +# OS ignores +*.DS_Store + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +poetry.lock + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +.idea/ + +# Visual Studio Code +.vscode diff --git a/order/README.MD b/order/README.MD new file mode 100644 index 0000000..153f280 --- /dev/null +++ b/order/README.MD @@ -0,0 +1,2 @@ +# JST-DJANGO +[Docs](https://docs.jscorp.uz) diff --git a/order/config/__init__.py b/order/config/__init__.py new file mode 100644 index 0000000..801fff4 --- /dev/null +++ b/order/config/__init__.py @@ -0,0 +1,3 @@ +from .celery import app + +__all__ = ["app"] diff --git a/order/config/asgi.py b/order/config/asgi.py new file mode 100644 index 0000000..f715434 --- /dev/null +++ b/order/config/asgi.py @@ -0,0 +1,23 @@ +import os + +from django.core.asgi import get_asgi_application + +asgi_application = get_asgi_application() +from config.env import env # noqa + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE")) + + +from channels.routing import ProtocolTypeRouter # noqa +from channels.routing import URLRouter # noqa + +# from core.apps.websocket.urls import websocket_urlpatterns # noqa +# from core.apps.websocket.middlewares import JWTAuthMiddlewareStack # noqa + +application = ProtocolTypeRouter( + { + "http": asgi_application, + # "websocket": JWTAuthMiddlewareStack(URLRouter(websocket_urlpatterns)), + } +) + diff --git a/order/config/celery.py b/order/config/celery.py new file mode 100644 index 0000000..1578806 --- /dev/null +++ b/order/config/celery.py @@ -0,0 +1,16 @@ +""" +Celery configurations +""" + +import os + +import celery +from config.env import env + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE")) + +app = celery.Celery("config") + +app.config_from_object("django.conf:settings", namespace="CELERY") + +app.autodiscover_tasks() diff --git a/order/config/conf/__init__.py b/order/config/conf/__init__.py new file mode 100644 index 0000000..d8f1296 --- /dev/null +++ b/order/config/conf/__init__.py @@ -0,0 +1,12 @@ +from .cache import * # noqa +from .celery import * # noqa +from .cron import * # noqa +from .jwt import * # noqa +from .logs import * # noqa +from .rest_framework import * # noqa +from .unfold import * # noqa +from .spectacular import * # noqa + +from .ckeditor import * # noqa +from .storage import * # noqa +from .channels import * # noqa \ No newline at end of file diff --git a/order/config/conf/apps.py b/order/config/conf/apps.py new file mode 100644 index 0000000..a34ee29 --- /dev/null +++ b/order/config/conf/apps.py @@ -0,0 +1,19 @@ +from config.env import env + +APPS = [ + "channels", + "cacheops", + "django_ckeditor_5", + "drf_spectacular", + "rest_framework", + "corsheaders", + "django_filters", + "django_redis", + "rest_framework_simplejwt", + "django_core", +] + +if env.str("PROJECT_ENV") == "debug": + APPS += [ + "silk", + ] diff --git a/order/config/conf/cache.py b/order/config/conf/cache.py new file mode 100644 index 0000000..cd724b5 --- /dev/null +++ b/order/config/conf/cache.py @@ -0,0 +1,26 @@ +from config.env import env + +CACHES = { + "default": { + "BACKEND": env.str("CACHE_BACKEND"), + "LOCATION": env.str("REDIS_URL"), + "TIMEOUT": env.str("CACHE_TIMEOUT"), + }, +} + +CACHE_MIDDLEWARE_SECONDS = env("CACHE_TIMEOUT") + + +CACHEOPS_REDIS = env.str("REDIS_URL") +CACHEOPS_DEFAULTS = { + "timeout": env.str("CACHE_TIMEOUT"), +} +CACHEOPS = { + # !NOTE: api => "you app name" + # "api.*": { + # "ops": "all", # Barcha turdagi so'rovlarni keshga olish + # "timeout": 60 * 5, # 5 daqiqa davomida saqlash + # }, +} +CACHEOPS_DEGRADE_ON_FAILURE = True +CACHEOPS_ENABLED = env.bool("CACHE_ENABLED", False) diff --git a/order/config/conf/celery.py b/order/config/conf/celery.py new file mode 100644 index 0000000..5f46855 --- /dev/null +++ b/order/config/conf/celery.py @@ -0,0 +1,7 @@ +CELERY_BEAT_SCHEDULE = { + # "test": { + # "task": "core.apps.home.tasks.demo.add", + # "schedule": 5.0, + # "args": (1, 2) + # }, +} diff --git a/order/config/conf/channels.py b/order/config/conf/channels.py new file mode 100644 index 0000000..d9f0597 --- /dev/null +++ b/order/config/conf/channels.py @@ -0,0 +1,8 @@ +CHANNEL_LAYERS = { + "default": { + "BACKEND": "channels_redis.core.RedisChannelLayer", + "CONFIG": { + "hosts": [("redis", 6379)], + }, + }, +} \ No newline at end of file diff --git a/order/config/conf/ckeditor.py b/order/config/conf/ckeditor.py new file mode 100644 index 0000000..654019c --- /dev/null +++ b/order/config/conf/ckeditor.py @@ -0,0 +1,147 @@ +import os +from pathlib import Path + +STATIC_URL = "/resources/static/" +MEDIA_URL = "/resources/media/" +MEDIA_ROOT = os.path.join(Path().parent.parent, "media") + +customColorPalette = [ + {"color": "hsl(4, 90%, 58%)", "label": "Red"}, + {"color": "hsl(340, 82%, 52%)", "label": "Pink"}, + {"color": "hsl(291, 64%, 42%)", "label": "Purple"}, + {"color": "hsl(262, 52%, 47%)", "label": "Deep Purple"}, + {"color": "hsl(231, 48%, 48%)", "label": "Indigo"}, + {"color": "hsl(207, 90%, 54%)", "label": "Blue"}, +] + +CKEDITOR_5_CONFIGS = { + "default": { + "toolbar": [ + "heading", + "|", + "bold", + "italic", + "link", + "bulletedList", + "numberedList", + "blockQuote", + "imageUpload", + ], + }, + "extends": { + "blockToolbar": [ + "paragraph", + "heading1", + "heading2", + "heading3", + "|", + "bulletedList", + "numberedList", + "|", + "blockQuote", + ], + "toolbar": [ + "heading", + "|", + "outdent", + "indent", + "|", + "bold", + "italic", + "link", + "underline", + "strikethrough", + "code", + "subscript", + "superscript", + "highlight", + "|", + "codeBlock", + "sourceEditing", + "insertImage", + "bulletedList", + "numberedList", + "todoList", + "|", + "blockQuote", + "imageUpload", + "|", + "fontSize", + "fontFamily", + "fontColor", + "fontBackgroundColor", + "mediaEmbed", + "removeFormat", + "insertTable", + ], + "image": { + "toolbar": [ + "imageTextAlternative", + "|", + "imageStyle:alignLeft", + "imageStyle:alignRight", + "imageStyle:alignCenter", + "imageStyle:side", + "|", + ], + "styles": [ + "full", + "side", + "alignLeft", + "alignRight", + "alignCenter", + ], + }, + "table": { + "contentToolbar": [ + "tableColumn", + "tableRow", + "mergeTableCells", + "tableProperties", + "tableCellProperties", + ], + "tableProperties": { + "borderColors": customColorPalette, + "backgroundColors": customColorPalette, + }, + "tableCellProperties": { + "borderColors": customColorPalette, + "backgroundColors": customColorPalette, + }, + }, + "heading": { + "options": [ + { + "model": "paragraph", + "title": "Paragraph", + "class": "ck-heading_paragraph", + }, + { + "model": "heading1", + "view": "h1", + "title": "Heading 1", + "class": "ck-heading_heading1", + }, + { + "model": "heading2", + "view": "h2", + "title": "Heading 2", + "class": "ck-heading_heading2", + }, + { + "model": "heading3", + "view": "h3", + "title": "Heading 3", + "class": "ck-heading_heading3", + }, + ] + }, + }, + "list": { + "properties": { + "styles": "true", + "startIndex": "true", + "reversed": "true", + } + }, +} diff --git a/order/config/conf/cron.py b/order/config/conf/cron.py new file mode 100644 index 0000000..e69de29 diff --git a/order/config/conf/jwt.py b/order/config/conf/jwt.py new file mode 100644 index 0000000..15d8970 --- /dev/null +++ b/order/config/conf/jwt.py @@ -0,0 +1,36 @@ +from datetime import timedelta + +from config.env import env + +SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60), + "REFRESH_TOKEN_LIFETIME": timedelta(days=30), + "ROTATE_REFRESH_TOKENS": False, + "BLACKLIST_AFTER_ROTATION": False, + "UPDATE_LAST_LOGIN": False, + "ALGORITHM": "HS256", + "SIGNING_KEY": env("DJANGO_SECRET_KEY"), + "VERIFYING_KEY": "", + "AUDIENCE": None, + "ISSUER": None, + "JSON_ENCODER": None, + "JWK_URL": None, + "LEEWAY": 0, + "AUTH_HEADER_TYPES": ("Bearer",), + "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", + "USER_ID_FIELD": "id", + "USER_ID_CLAIM": "user_id", + "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), + "TOKEN_TYPE_CLAIM": "token_type", + "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser", + "JTI_CLAIM": "jti", + "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", + "SLIDING_TOKEN_LIFETIME": timedelta(minutes=60), + "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=30), + "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer", + "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer", + "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer", + "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer", + "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer", + "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", +} diff --git a/order/config/conf/logs.py b/order/config/conf/logs.py new file mode 100644 index 0000000..5245ac6 --- /dev/null +++ b/order/config/conf/logs.py @@ -0,0 +1,29 @@ +# settings.py faylida + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "format": "{levelname} {asctime} {module} {message}", + "style": "{", + }, + }, + "handlers": { + "daily_rotating_file": { + "level": "INFO", + "class": "logging.handlers.TimedRotatingFileHandler", + "filename": "resources/logs/django.log", # Fayl nomi (kunlik fayllar uchun avtomatik yoziladi) + "when": "midnight", # Har kecha log fayli yangilanadi + "backupCount": 30, # 30 kunlik loglar saqlanadi, 1 oydan keyin eski fayllar o'chiriladi + "formatter": "verbose", + }, + }, + "loggers": { + "django": { + "handlers": ["daily_rotating_file"], + "level": "INFO", + "propagate": True, + }, + }, +} diff --git a/order/config/conf/modules.py b/order/config/conf/modules.py new file mode 100644 index 0000000..a429f38 --- /dev/null +++ b/order/config/conf/modules.py @@ -0,0 +1 @@ +MODULES = [] diff --git a/order/config/conf/navigation.py b/order/config/conf/navigation.py new file mode 100644 index 0000000..2083489 --- /dev/null +++ b/order/config/conf/navigation.py @@ -0,0 +1,31 @@ +from django.urls import reverse_lazy +from django.utils.translation import gettext_lazy as _ + +PAGES = [ + { + "seperator": False, + "items": [ + { + "title": _("Home page"), + "icon": "home", + "link": reverse_lazy("admin:index"), + } + ], + }, + { + "title": _("Auth"), + "separator": True, # Top border + "items": [ + { + "title": _("Users"), + "icon": "group", + "link": reverse_lazy("admin:http_user_changelist"), + }, + { + "title": _("Group"), + "icon": "group", + "link": reverse_lazy("admin:auth_group_changelist"), + }, + ], + }, +] diff --git a/order/config/conf/rest_framework.py b/order/config/conf/rest_framework.py new file mode 100644 index 0000000..fbec6fe --- /dev/null +++ b/order/config/conf/rest_framework.py @@ -0,0 +1,9 @@ +from typing import Any, Union + +REST_FRAMEWORK: Union[Any] = { + "DEFAULT_AUTHENTICATION_CLASSES": ("rest_framework_simplejwt.authentication.JWTAuthentication",), + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", + "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"], + "DEFAULT_PAGINATION_CLASS": "django_core.paginations.CustomPagination", + "PAGE_SIZE": 10, +} diff --git a/order/config/conf/spectacular.py b/order/config/conf/spectacular.py new file mode 100644 index 0000000..2be491b --- /dev/null +++ b/order/config/conf/spectacular.py @@ -0,0 +1,31 @@ +SPECTACULAR_SETTINGS = { + "TITLE": "Your Project API", + "DESCRIPTION": "Your project description", + "VERSION": "1.0.0", + "SERVE_INCLUDE_SCHEMA": False, + "CAMELIZE_NAMES": True, + "POSTPROCESSING_HOOKS": ["config.conf.spectacular.custom_postprocessing_hook"], +} + + +def custom_postprocessing_hook(result, generator, request, public): + """ + Customizes the API schema to wrap all responses in a standard format. + """ + for path, methods in result.get("paths", {}).items(): + for method, operation in methods.items(): + if "responses" in operation: + for status_code, response in operation["responses"].items(): + if "content" in response: + for content_type, content in response["content"].items(): + # Wrap original schema + original_schema = content.get("schema", {}) + response["content"][content_type]["schema"] = { + "type": "object", + "properties": { + "status": {"type": "boolean", "example": True}, + "data": original_schema, + }, + "required": ["status", "data"], + } + return result diff --git a/order/config/conf/storage.py b/order/config/conf/storage.py new file mode 100644 index 0000000..5d59a85 --- /dev/null +++ b/order/config/conf/storage.py @@ -0,0 +1,23 @@ +from config.env import env +from core.utils.storage import Storage + +AWS_ACCESS_KEY_ID = env.str("STORAGE_ID") +AWS_SECRET_ACCESS_KEY = env.str("STORAGE_KEY") +AWS_S3_ENDPOINT_URL = env.str("STORAGE_URL") +AWS_S3_CUSTOM_DOMAIN = env.str("STORAGE_PATH") +AWS_S3_URL_PROTOCOL = env.str("STORAGE_PROTOCOL", "https:") +AWS_S3_FILE_OVERWRITE = False + +default_storage = Storage(env.str("STORAGE_DEFAULT"), "default") +static_storage = Storage(env.str("STORAGE_STATIC"), "static") + +STORAGES = { + "default": { + "BACKEND": default_storage.get_backend(), + "OPTIONS": default_storage.get_options(), + }, + "staticfiles": { + "BACKEND": static_storage.get_backend(), + "OPTIONS": static_storage.get_options(), + }, +} diff --git a/order/config/conf/unfold.py b/order/config/conf/unfold.py new file mode 100644 index 0000000..cfbd93a --- /dev/null +++ b/order/config/conf/unfold.py @@ -0,0 +1,41 @@ +from . import navigation + +UNFOLD = { + "DASHBOARD_CALLBACK": "django_core.views.dashboard_callback", + "SITE_TITLE": None, + "SHOW_LANGUAGES": True, + "SITE_HEADER": None, + "SITE_URL": "/", + "SITE_SYMBOL": "speed", # symbol from icon set + "SHOW_HISTORY": True, # show/hide "History" button, default: True + "SHOW_VIEW_ON_SITE": True, + "COLORS": { + "primary": { + "50": "220 255 230", + "100": "190 255 200", + "200": "160 255 170", + "300": "130 255 140", + "400": "100 255 110", + "500": "70 255 80", + "600": "50 225 70", + "700": "40 195 60", + "800": "30 165 50", + "900": "20 135 40", + "950": "10 105 30", + }, + }, + "EXTENSIONS": { + "modeltranslation": { + "flags": { + "en": "🇬🇧", + "uz": "🇺🇿", + "ru": "🇷🇺", + }, + }, + }, + "SIDEBAR": { + "show_search": True, # Search in applications and models names + "show_all_applications": True, + # "navigation": navigation.PAGES, # Pagelarni qo'lda qo'shish + }, +} diff --git a/order/config/env.py b/order/config/env.py new file mode 100644 index 0000000..f37c164 --- /dev/null +++ b/order/config/env.py @@ -0,0 +1,28 @@ +""" +Default value for environ variable +""" + +import os + +import environ + +environ.Env.read_env(os.path.join(".env")) + +env = environ.Env( + DEBUG=(bool, False), + CACHE_TIME=(int, 180), + OTP_EXPIRE_TIME=(int, 2), + VITE_LIVE=(bool, False), + ALLOWED_HOSTS=(str, "localhost"), + CSRF_TRUSTED_ORIGINS=(str, "localhost"), + DJANGO_SETTINGS_MODULE=(str, "config.settings.local"), + CACHE_TIMEOUT=(int, 120), + CACHE_ENABLED=(bool, False), + VITE_PORT=(int, 5173), + VITE_HOST=(str, "vite"), + NGROK_AUTHTOKEN=(str, "TOKEN"), + BOT_TOKEN=(str, "TOKEN"), + OTP_MODULE="core.services.otp", + OTP_SERVICE="EskizService", + PROJECT_ENV=(str, "prod"), +) diff --git a/order/config/settings/__init__.py b/order/config/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/config/settings/common.py b/order/config/settings/common.py new file mode 100644 index 0000000..42ba66b --- /dev/null +++ b/order/config/settings/common.py @@ -0,0 +1,172 @@ +import os +import pathlib +from typing import List, Union + +from config.conf import * # noqa +from config.conf.apps import APPS +from config.conf.modules import MODULES +from config.env import env +from django.utils.translation import gettext_lazy as _ +from rich.traceback import install + +install(show_locals=True) +BASE_DIR = pathlib.Path(__file__).resolve().parent.parent.parent + +SECRET_KEY = env.str("DJANGO_SECRET_KEY") +DEBUG = env.bool("DEBUG") + +ALLOWED_HOSTS: Union[List[str]] = ["*"] + +if env.bool("PROTOCOL_HTTPS", False): + SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + +DATABASES = { + "default": { + "ENGINE": env.str("DB_ENGINE"), + "NAME": env.str("DB_NAME"), + "USER": env.str("DB_USER"), + "PASSWORD": env.str("DB_PASSWORD"), + "HOST": env.str("DB_HOST"), + "PORT": env.str("DB_PORT"), + } +} + +PASSWORD_HASHERS = [ + "django.contrib.auth.hashers.BCryptPasswordHasher", +] + +INSTALLED_APPS = [ + "modeltranslation", + "unfold", + "unfold.contrib.filters", + "unfold.contrib.forms", + "unfold.contrib.guardian", + "unfold.contrib.simple_history", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", +] + APPS + +MODULES = [app for app in MODULES if isinstance(app, str)] + +for module_path in MODULES: + INSTALLED_APPS.append("{}.apps.ModuleConfig".format(module_path)) + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "corsheaders.middleware.CorsMiddleware", # Cors middleware + "django.middleware.locale.LocaleMiddleware", # Locale middleware + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] +if env.str("PROJECT_ENV") == "debug": + MIDDLEWARE += [ + "silk.middleware.SilkyMiddleware", + ] + + +ROOT_URLCONF = "config.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(BASE_DIR, "resources/templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] +# fmt: off + +WSGI_APPLICATION = "config.wsgi.application" + +# fmt: on + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.{}".format(validator) + } for validator in [ + "UserAttributeSimilarityValidator", + "MinimumLengthValidator", + "CommonPasswordValidator", + "NumericPasswordValidator" + ] +] + +TIME_ZONE = "Asia/Tashkent" +USE_I18N = True +USE_TZ = True +STATIC_URL = "resources/static/" +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + +# Date formats +## +DATE_FORMAT = "d.m.y" +TIME_FORMAT = "H:i:s" +DATE_INPUT_FORMATS = ["%d.%m.%Y", "%Y.%d.%m", "%Y.%d.%m"] + + +SEEDERS = ["core.apps.accounts.seeder.UserSeeder"] + +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "resources/static"), +] + +CORS_ORIGIN_ALLOW_ALL = True + +STATIC_ROOT = os.path.join(BASE_DIR, "resources/staticfiles") +VITE_APP_DIR = os.path.join(BASE_DIR, "resources/static/vite") + +LANGUAGES = ( + ("ru", _("Russia")), + ("en", _("English")), + ("uz", _("Uzbek")), +) +LOCALE_PATHS = [os.path.join(BASE_DIR, "resources/locale")] + +LANGUAGE_CODE = "uz" + +MEDIA_ROOT = os.path.join(BASE_DIR, "resources/media") # Media files +MEDIA_URL = "/resources/media/" + +CELERY_BROKER_URL = env("REDIS_URL") +CELERY_RESULT_BACKEND = env("REDIS_URL") + +ALLOWED_HOSTS += env("ALLOWED_HOSTS").split(",") +CSRF_TRUSTED_ORIGINS = env("CSRF_TRUSTED_ORIGINS").split(",") +SILKY_AUTHORISATION = True +SILKY_PYTHON_PROFILER = True + +MODELTRANSLATION_LANGUAGES = ("uz", "ru", "en") +MODELTRANSLATION_DEFAULT_LANGUAGE = "uz" + + + +JST_LANGUAGES = [ + { + "code": "uz", + "name": "Uzbek", + "is_default": True, + }, + { + "code": "en", + "name": "English", + }, + { + "code": "ru", + "name": "Russia", + } +] diff --git a/order/config/settings/local.py b/order/config/settings/local.py new file mode 100644 index 0000000..7394e18 --- /dev/null +++ b/order/config/settings/local.py @@ -0,0 +1,11 @@ +from config.settings.common import * # noqa +from config.settings.common import (ALLOWED_HOSTS, INSTALLED_APPS, + REST_FRAMEWORK) + +INSTALLED_APPS += ["django_extensions"] + +ALLOWED_HOSTS += ["127.0.0.1", "192.168.100.26"] + +REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = { + "user": "60/min", +} diff --git a/order/config/settings/production.py b/order/config/settings/production.py new file mode 100644 index 0000000..d802ed7 --- /dev/null +++ b/order/config/settings/production.py @@ -0,0 +1,6 @@ +from config.settings.common import * # noqa +from config.settings.common import ALLOWED_HOSTS, REST_FRAMEWORK + +ALLOWED_HOSTS += ["192.168.100.26", "80.90.178.156"] + +REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = {"user": "60/min"} diff --git a/order/config/urls.py b/order/config/urls.py new file mode 100644 index 0000000..d555038 --- /dev/null +++ b/order/config/urls.py @@ -0,0 +1,55 @@ +""" +All urls configurations tree +""" + +from django.conf import settings +from config.env import env +from django.contrib import admin +from django.urls import include, path, re_path +from django.views.static import serve +from drf_spectacular.views import (SpectacularAPIView, SpectacularRedocView, + SpectacularSwaggerView) + +################ +# My apps url +################ +urlpatterns = [ + +] + + +################ +# Library urls +################ +urlpatterns += [ + path("admin/", admin.site.urls), + path("accounts/", include("django.contrib.auth.urls")), + path("i18n/", include("django.conf.urls.i18n")), + + path("ckeditor5/", include("django_ckeditor_5.urls"), name="ck_editor_5_upload_file"), +] + +################ +# Project env debug mode +################ +if env.str("PROJECT_ENV") == "debug": + urlpatterns += [ + path('silk/', include('silk.urls', namespace='silk')) + ] + + ################ + # Swagger urls + ################ + urlpatterns += [ + path("schema/", SpectacularAPIView.as_view(), name="schema"), + path("swagger/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger-ui"), + path("redoc/", SpectacularRedocView.as_view(url_name="schema"), name="redoc"), + ] + +################ +# Media urls +################ +urlpatterns += [ + re_path(r"static/(?P.*)", serve, {"document_root": settings.STATIC_ROOT}), + re_path(r"media/(?P.*)", serve, {"document_root": settings.MEDIA_ROOT}), +] diff --git a/order/config/wsgi.py b/order/config/wsgi.py new file mode 100644 index 0000000..ab1662c --- /dev/null +++ b/order/config/wsgi.py @@ -0,0 +1,8 @@ +import os + +from config.env import env +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE")) + +application = get_wsgi_application() diff --git a/order/core/__init__.py b/order/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/core/apps/__init__.py b/order/core/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/core/services/__init__.py b/order/core/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/core/utils/__init__.py b/order/core/utils/__init__.py new file mode 100644 index 0000000..f10075c --- /dev/null +++ b/order/core/utils/__init__.py @@ -0,0 +1,3 @@ +from .cache import * # noqa +from .console import * # noqa +from .core import * # noqa diff --git a/order/core/utils/cache.py b/order/core/utils/cache.py new file mode 100644 index 0000000..2c00899 --- /dev/null +++ b/order/core/utils/cache.py @@ -0,0 +1,18 @@ +import hashlib + +from django.core.cache import cache + +from config.env import env + + +class Cache: + def remember(self, func, key: str, timeout=None, *args, **kwargs): + cache_enabled = env.bool("CACHE_ENABLED") + key = hashlib.md5(key.encode("utf-8")).hexdigest() + response = cache.get(key) + if not cache_enabled: + return func(*args, **kwargs) + elif response is None: + response = func(*args, **kwargs) + cache.set(key, response, env.int("CACHE_TIME") if timeout is None else timeout) + return response diff --git a/order/core/utils/console.py b/order/core/utils/console.py new file mode 100644 index 0000000..a296d66 --- /dev/null +++ b/order/core/utils/console.py @@ -0,0 +1,79 @@ +import logging +import os +from typing import Any, Union + +from django.conf import settings +from django.core import management + + +class Console(management.BaseCommand): + """ + Console logging class + """ + + def get_stdout(self): + base_command = management.BaseCommand() + return base_command.stdout + + def get_style(self): + base_command = management.BaseCommand() + return base_command.style + + def success(self, message): + logging.debug(message) + self.get_stdout().write(self.get_style().SUCCESS(message)) + + def error(self, message): + logging.error(message) + self.get_stdout().write(self.get_style().ERROR(message)) + + def log(self, message): + self.get_stdout().write( + self.get_style().ERROR( + "\n{line}\n{message}\n{line}\n".format( + message=message, line="=" * len(message) + ) + ) + ) + + +class BaseMake(management.BaseCommand): + path: str + + def __init__(self, *args, **options): + super().__init__(*args, **options) + self.console = Console() + + def add_arguments(self, parser): + parser.add_argument("name") + + def handle(self, *args, **options): + name = options.get("name") + if name is None: + name = "" + + stub = open(os.path.join(settings.BASE_DIR, f"resources/stub/{self.path}.stub")) + data: Union[Any] = stub.read() + stub.close() + + stub = data.replace("{{name}}", name or "") + + + core_http_path = os.path.join(settings.BASE_DIR, "core/http") + if os.path.exists( + os.path.join(core_http_path, f"{self.path}/{name.lower()}.py") + ): # noqa + self.console.error(f"{self.name} already exists") + return + + if not os.path.exists(os.path.join(core_http_path, self.path)): + os.makedirs(os.path.join(core_http_path, self.path)) + + file = open( + os.path.join(core_http_path, f"{self.path}/{name.lower()}.py"), + "w+", + ) + file.write(stub) # type: ignore + file.close() + + self.console.success(f"{self.name} created") diff --git a/order/core/utils/core.py b/order/core/utils/core.py new file mode 100644 index 0000000..04fdbed --- /dev/null +++ b/order/core/utils/core.py @@ -0,0 +1,6 @@ +class Helper: + """ + Helper class to handle index + """ + + pass diff --git a/order/core/utils/storage.py b/order/core/utils/storage.py new file mode 100644 index 0000000..50e6d33 --- /dev/null +++ b/order/core/utils/storage.py @@ -0,0 +1,33 @@ +from typing import Optional, Union + +from config.env import env + + +class Storage: + + storages = ["AWS", "MINIO", "FILE", "STATIC"] + + def __init__(self, storage: Union[str], storage_type: Union[str] = "default") -> None: + self.storage = storage + self.sorage_type = storage_type + if storage not in self.storages: + raise ValueError(f"Invalid storage type: {storage}") + + def get_backend(self) -> Optional[str]: + match self.storage: + case "AWS" | "MINIO": + return "storages.backends.s3boto3.S3Boto3Storage" + case "FILE": + return "django.core.files.storage.FileSystemStorage" + case "STATIC": + return "django.contrib.staticfiles.storage.StaticFilesStorage" + + def get_options(self) -> Optional[str]: + match self.storage: + case "AWS" | "MINIO": + if self.sorage_type == "default": + return {"bucket_name": env.str("STORAGE_BUCKET_MEDIA")} + elif self.sorage_type == "static": + return {"bucket_name": env.str("STORAGE_BUCKET_STATIC")} + case _: + return {} diff --git a/order/docker-compose.yml b/order/docker-compose.yml new file mode 100644 index 0000000..945920e --- /dev/null +++ b/order/docker-compose.yml @@ -0,0 +1,53 @@ +networks: + lamenu: + external: true + +volumes: + pg_data: null + pycache: null + +services: + order-nginx: + labels: + - "traefik.enable=true" + - "traefik.http.routers.order.rule=PathPrefix(`/order`)" + - "traefik.http.routers.order.entrypoints=web" + - "traefik.http.services.order.loadbalancer.server.port=80" + # - "traefik.http.middlewares.order-strip-prefix.stripPrefix.prefixes=/order" + # - "traefik.http.routers.order.middlewares=order-strip-prefix" + networks: + - lamenu + volumes: + - ./resources/layout/nginx.conf:/etc/nginx/nginx.conf + - ./resources/:/usr/share/nginx/html/resources/ + build: + context: . + dockerfile: ./docker/Dockerfile.nginx + depends_on: + - order + order: + networks: + - lamenu + build: + context: . + dockerfile: ./docker/Dockerfile.web + restart: always + command: ${COMMAND:-sh ./entrypoint.sh} + environment: + - PYTHONPYCACHEPREFIX=/var/cache/pycache + volumes: + - .:/code + - pycache:/var/cache/pycache + depends_on: + - order-db + order-db: + networks: + - lamenu + image: postgres:16 + restart: always + environment: + POSTGRES_DB: django + POSTGRES_USER: postgres + POSTGRES_PASSWORD: '2309' + volumes: + - pg_data:/var/lib/postgresql/data diff --git a/order/docker/Dockerfile.nginx b/order/docker/Dockerfile.nginx new file mode 100644 index 0000000..22a1599 --- /dev/null +++ b/order/docker/Dockerfile.nginx @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY ./resources/layout/nginx.conf /etc/nginx/nginx.conf diff --git a/order/docker/Dockerfile.web b/order/docker/Dockerfile.web new file mode 100644 index 0000000..1fcf699 --- /dev/null +++ b/order/docker/Dockerfile.web @@ -0,0 +1,9 @@ +FROM jscorptech/django:v0.5 + +WORKDIR /code + +COPY ./ /code + +RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt + +CMD ["sh", "./resources/scripts/entrypoint.sh"] diff --git a/order/jst.json b/order/jst.json new file mode 100644 index 0000000..e87c706 --- /dev/null +++ b/order/jst.json @@ -0,0 +1,8 @@ +{ + "dirs": { + "apps": "./core/apps/", + "locale": "./resources/locale/" + }, + "stubs": {}, + "apps": "core.apps." +} \ No newline at end of file diff --git a/order/manage.py b/order/manage.py new file mode 100644 index 0000000..67c98de --- /dev/null +++ b/order/manage.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + +from config.env import env + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE")) + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/order/pyproject.toml b/order/pyproject.toml new file mode 100644 index 0000000..e7de07c --- /dev/null +++ b/order/pyproject.toml @@ -0,0 +1,21 @@ +[tool.black] +line-length = 120 + +[tool.isort] +profile = "black" +line_length = 120 + +[tool.pytest.ini_options] +DJANGO_SETTINGS_MODULE = "config.settings.local" +python_files = "tests.py test_*.py *_tests.py" +filterwarnings = [ + "ignore::DeprecationWarning", + "ignore::PendingDeprecationWarning", + "ignore::ResourceWarning", + "ignore::Warning" # This line will ignore all warnings +] + + +[tool.flake8] +max-line-length = 120 +ignore = ["E701", "E704", "W503"] diff --git a/order/requirements.txt b/order/requirements.txt new file mode 100644 index 0000000..7430bbb --- /dev/null +++ b/order/requirements.txt @@ -0,0 +1,45 @@ +backports.tarfile==1.2.0 +celery==5.4.0 +django-cors-headers==4.6.0 +django-environ==0.11.2 +django-extensions==3.2.3 +django-filter==24.3 +django-redis==5.4.0 +django-unfold==0.42.0 +djangorestframework-simplejwt==5.3.1 +drf-spectacular==0.28.0 +importlib-metadata==8.5.0 +importlib-resources==6.4.5 +inflect==7.3.1 +jaraco.collections==5.1.0 +packaging==24.2 +pip-chill==1.0.3 +platformdirs==4.3.6 +psycopg2-binary==2.9.10 +tomli==2.2.1 +uvicorn==0.32.1 +jst-django-core~=1.1.8 +rich +pydantic +bcrypt + + + +django-modeltranslation~=0.19.11 +django-ckeditor-5==0.2.15 +channels==4.2.0 + +django-cacheops~=7.1 +django-silk + +# !NOTE: on-server +# gunicorn + + +django-storages +boto3 + + +# !NOTE: on-websocket +# websockets +# channels-redis diff --git a/order/resources/.gitignore b/order/resources/.gitignore new file mode 100644 index 0000000..7627088 --- /dev/null +++ b/order/resources/.gitignore @@ -0,0 +1 @@ +staticfiles/ \ No newline at end of file diff --git a/order/resources/layout/.flake8 b/order/resources/layout/.flake8 new file mode 100644 index 0000000..4088dec --- /dev/null +++ b/order/resources/layout/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 120 +ignore = E701, E704, W503 diff --git a/order/resources/layout/Dockerfile.alpine b/order/resources/layout/Dockerfile.alpine new file mode 100644 index 0000000..f57c7bc --- /dev/null +++ b/order/resources/layout/Dockerfile.alpine @@ -0,0 +1,13 @@ +FROM python:3.13-alpine + +ENV PYTHONPYCACHEPREFIX=/dev/null + +RUN apk update && apk add git gettext + +WORKDIR /code + +COPY requirements.txt /code/requirements.txt + +RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt + +CMD ["sh", "./entrypoint.sh"] diff --git a/order/resources/layout/Dockerfile.nginx b/order/resources/layout/Dockerfile.nginx new file mode 100644 index 0000000..22a1599 --- /dev/null +++ b/order/resources/layout/Dockerfile.nginx @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY ./resources/layout/nginx.conf /etc/nginx/nginx.conf diff --git a/order/resources/layout/mypy.ini b/order/resources/layout/mypy.ini new file mode 100644 index 0000000..6c53a26 --- /dev/null +++ b/order/resources/layout/mypy.ini @@ -0,0 +1,5 @@ +[mypy] +check_untyped_defs = True + +[mypy-requests.*] +ignore_missing_imports = True \ No newline at end of file diff --git a/order/resources/layout/nginx.conf b/order/resources/layout/nginx.conf new file mode 100644 index 0000000..89280da --- /dev/null +++ b/order/resources/layout/nginx.conf @@ -0,0 +1,54 @@ +# Main configuration block +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + # Logging settings (optional) + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + client_max_body_size 1024M; + + # Server block for handling requests + server { + listen 80; + + server_name _; + + location / { + proxy_pass http://order:8000; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + } + location /ws/ { + proxy_pass http://order:8000; # Uvicorn serveri ishga tushadigan port + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $http_host; + } + + location /resources/static/ { + alias /usr/share/nginx/html/resources/staticfiles/; + } + + location /resources/media/ { + alias /usr/share/nginx/html/resources/media/; + } + } +} diff --git a/order/resources/locale/.gitkeep b/order/resources/locale/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/order/resources/locale/en/LC_MESSAGES/django.po b/order/resources/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..acc28e8 --- /dev/null +++ b/order/resources/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,49 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-02-15 16:40+0500\n" +"PO-Revision-Date: 2024-02-09 15:09+0500\n" +"Last-Translator: \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Translated-Using: django-rosetta 0.10.0\n" + +#: config/settings/common.py:148 +msgid "Russia" +msgstr "" + +#: config/settings/common.py:149 +msgid "English" +msgstr "" + +#: config/settings/common.py:150 +msgid "Uzbek" +msgstr "" + +#: core/http/admin/index.py:20 +msgid "Custom Field" +msgstr "" + +#: core/http/tasks/index.py:13 +#, python-format +msgid "Sizning Tasdiqlash ko'dingiz: %(code)s" +msgstr "" + +#: resources/templates/user/home.html:18 +msgid "Django" +msgstr "" + +#: resources/templates/user/home.html:19 +msgid "Assalomu aleykum" +msgstr "" diff --git a/order/resources/locale/ru/LC_MESSAGES/django.po b/order/resources/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000..a039baa --- /dev/null +++ b/order/resources/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,51 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-02-15 16:40+0500\n" +"PO-Revision-Date: 2024-02-09 15:09+0500\n" +"Last-Translator: \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || " +"(n%100>=11 && n%100<=14)? 2 : 3);\n" +"X-Translated-Using: django-rosetta 0.10.0\n" + +#: config/settings/common.py:148 +msgid "Russia" +msgstr "" + +#: config/settings/common.py:149 +msgid "English" +msgstr "" + +#: config/settings/common.py:150 +msgid "Uzbek" +msgstr "" + +#: core/http/admin/index.py:20 +msgid "Custom Field" +msgstr "" + +#: core/http/tasks/index.py:13 +#, python-format +msgid "Sizning Tasdiqlash ko'dingiz: %(code)s" +msgstr "" + +#: resources/templates/user/home.html:18 +msgid "Django" +msgstr "" + +#: resources/templates/user/home.html:19 +msgid "Assalomu aleykum" +msgstr "" diff --git a/order/resources/locale/uz/LC_MESSAGES/django.po b/order/resources/locale/uz/LC_MESSAGES/django.po new file mode 100644 index 0000000..c3a7ef5 --- /dev/null +++ b/order/resources/locale/uz/LC_MESSAGES/django.po @@ -0,0 +1,55 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-02-15 16:40+0500\n" +"PO-Revision-Date: 2024-02-10 22:46+0500\n" +"Last-Translator: \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Translated-Using: django-rosetta 0.10.0\n" + +#: config/settings/common.py:148 +msgid "Russia" +msgstr "" + +#: config/settings/common.py:149 +msgid "English" +msgstr "" + +#: config/settings/common.py:150 +msgid "Uzbek" +msgstr "" + +#: core/http/admin/index.py:20 +msgid "Custom Field" +msgstr "" + +#: core/http/tasks/index.py:13 +#, python-format +msgid "Sizning Tasdiqlash ko'dingiz: %(code)s" +msgstr "" + +#: resources/templates/user/home.html:18 +msgid "Django" +msgstr "" + +#: resources/templates/user/home.html:19 +msgid "Assalomu aleykum" +msgstr "" + +#~ msgid "Home" +#~ msgstr "Bosh sahifa" + +#~ msgid "Homes" +#~ msgstr "Bosh sahifa" diff --git a/order/resources/logs/.gitignore b/order/resources/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/order/resources/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/order/resources/media/.gitignore b/order/resources/media/.gitignore new file mode 100644 index 0000000..a3a0c8b --- /dev/null +++ b/order/resources/media/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/order/resources/scripts/backup.sh b/order/resources/scripts/backup.sh new file mode 100644 index 0000000..5bac180 --- /dev/null +++ b/order/resources/scripts/backup.sh @@ -0,0 +1,5 @@ +file=/tmp/db-$(/usr/bin/date +\%Y-%m-%d-%H:%M:%S).sql +container=postgres +/usr/bin/docker container exec $container pg_dump -U postgres django > $file +mc cp $file b2/buket-name +rm $file \ No newline at end of file diff --git a/order/resources/scripts/entrypoint-server.sh b/order/resources/scripts/entrypoint-server.sh new file mode 100644 index 0000000..d0233fc --- /dev/null +++ b/order/resources/scripts/entrypoint-server.sh @@ -0,0 +1,11 @@ +#!/bin/bash +python3 manage.py collectstatic --noinput +python3 manage.py migrate --noinput + +gunicorn config.wsgi:application -b 0.0.0.0:8000 --workers $(($(nproc) * 2 + 1)) + + + +exit $? + + diff --git a/order/resources/scripts/entrypoint.sh b/order/resources/scripts/entrypoint.sh new file mode 100644 index 0000000..b5e6e01 --- /dev/null +++ b/order/resources/scripts/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash +python3 manage.py collectstatic --noinput +python3 manage.py migrate --noinput + +uvicorn config.asgi:application --host 0.0.0.0 --port 8000 --reload --reload-dir core --reload-dir config + + + +exit $? + + diff --git a/order/resources/static/css/app.css b/order/resources/static/css/app.css new file mode 100644 index 0000000..e69de29 diff --git a/order/resources/static/css/error.css b/order/resources/static/css/error.css new file mode 100644 index 0000000..11201a8 --- /dev/null +++ b/order/resources/static/css/error.css @@ -0,0 +1,109 @@ +* { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +body { + padding: 0; + margin: 0; +} + +#notfound { + position: relative; + height: 100vh; +} + +#notfound .notfound { + position: absolute; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} + +.notfound { + max-width: 710px; + width: 100%; + padding-left: 190px; + line-height: 1.4; +} + +.notfound .notfound-404 { + position: absolute; + left: 0; + top: 0; + width: 150px; + height: 150px; +} + +.notfound .notfound-404 h1 { + font-family: 'Passion One', cursive; + color: #00b5c3; + font-size: 150px; + letter-spacing: 15.5px; + margin: 0px; + font-weight: 900; + position: absolute; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} + +.notfound h2 { + font-family: 'Raleway', sans-serif; + color: #292929; + font-size: 28px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 2.5px; + margin-top: 0; +} + +.notfound p { + font-family: 'Raleway', sans-serif; + font-size: 14px; + font-weight: 400; + margin-top: 0; + margin-bottom: 15px; + color: #333; +} + +.notfound a { + font-family: 'Raleway', sans-serif; + font-size: 14px; + text-decoration: none; + text-transform: uppercase; + background: #fff; + display: inline-block; + padding: 15px 30px; + border-radius: 40px; + color: #292929; + font-weight: 700; + -webkit-box-shadow: 0px 4px 15px -5px rgba(0, 0, 0, 0.3); + box-shadow: 0px 4px 15px -5px rgba(0, 0, 0, 0.3); + -webkit-transition: 0.2s all; + transition: 0.2s all; +} + +.notfound a:hover { + color: #fff; + background-color: #00b5c3; +} + +@media only screen and (max-width: 480px) { + .notfound { + text-align: center; + } + .notfound .notfound-404 { + position: relative; + width: 100%; + margin-bottom: 15px; + } + .notfound { + padding-left: 15px; + padding-right: 15px; + } +} diff --git a/order/resources/static/css/input.css b/order/resources/static/css/input.css new file mode 100644 index 0000000..04b35af --- /dev/null +++ b/order/resources/static/css/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/order/resources/static/css/jazzmin.css b/order/resources/static/css/jazzmin.css new file mode 100644 index 0000000..8b8be66 --- /dev/null +++ b/order/resources/static/css/jazzmin.css @@ -0,0 +1,5 @@ +.login-logo img { + border-radius: 100%; + width: 100px; + height: 100px; +} \ No newline at end of file diff --git a/order/resources/static/css/output.css b/order/resources/static/css/output.css new file mode 100644 index 0000000..99bc6dc --- /dev/null +++ b/order/resources/static/css/output.css @@ -0,0 +1,772 @@ +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +/* +! tailwindcss v3.4.14 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden]:where(:not([hidden="until-found"])) { + display: none; +} + +.static { + position: static; +} + +.m-2 { + margin: 0.5rem; +} + +.mx-4 { + margin-left: 1rem; + margin-right: 1rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.ml-1 { + margin-left: 0.25rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mt-5 { + margin-top: 1.25rem; +} + +.block { + display: block; +} + +.inline-block { + display: inline-block; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.h-\[100vh\] { + height: 100vh; +} + +.w-\[100vw\] { + width: 100vw; +} + +.w-full { + width: 100%; +} + +.cursor-pointer { + cursor: pointer; +} + +.grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.items-center { + align-items: center; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-center { + justify-content: center; +} + +.gap-8 { + gap: 2rem; +} + +.gap-x-3 { + -moz-column-gap: 0.75rem; + column-gap: 0.75rem; +} + +.whitespace-nowrap { + white-space: nowrap; +} + +.rounded { + border-radius: 0.25rem; +} + +.border { + border-width: 1px; +} + +.border-black { + --tw-border-opacity: 1; + border-color: rgb(0 0 0 / var(--tw-border-opacity)); +} + +.bg-blue-100 { + --tw-bg-opacity: 1; + background-color: rgb(219 234 254 / var(--tw-bg-opacity)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.p-4 { + padding: 1rem; +} + +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.px-\[40px\] { + padding-left: 40px; + padding-right: 40px; +} + +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.text-center { + text-align: center; +} + +.text-\[20px\] { + font-size: 20px; +} + +.text-\[25px\] { + font-size: 25px; +} + +.text-\[30px\] { + font-size: 30px; +} + +.text-\[40px\] { + font-size: 40px; +} + +.font-\[400\] { + font-weight: 400; +} + +.font-\[600\] { + font-weight: 600; +} + +.font-bold { + font-weight: 700; +} + +.font-semibold { + font-weight: 600; +} + +.uppercase { + text-transform: uppercase; +} + +.leading-normal { + line-height: 1.5; +} + +.text-black { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); +} + +.text-blue-500 { + --tw-text-opacity: 1; + color: rgb(59 130 246 / var(--tw-text-opacity)); +} + +.text-red-500 { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); +} + +@media (min-width: 640px) { + .sm\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 768px) { + .md\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (min-width: 1024px) { + .lg\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} diff --git a/order/resources/static/images/logo.png b/order/resources/static/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..57ac67eec80f23a0ea8c2fc7c946588a4d8f5d35 GIT binary patch literal 39362 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]%23n2&SNM2Gj_-SWIm&t|Q0ArH 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 ({ + count: 2309 +}) \ No newline at end of file diff --git a/order/resources/static/js/customer.js b/order/resources/static/js/customer.js new file mode 100644 index 0000000..06bacfb --- /dev/null +++ b/order/resources/static/js/customer.js @@ -0,0 +1,49 @@ + +class Changer { + constructor() { + this.inputs = []; + + this.legal = [ + "bank_mfo", + "bank_name", + "bank_account", + "name", + "director_name", + "responsible_person", + "inn" + ]; + + this.physical = [ + "passport_series", + "jshir", + "first_name", + "last_name", + ] + this.legal.concat(this.physical).forEach((item) => { + this.inputs[item] = document.querySelector(`#id_${item}`).closest(".form-row"); + }) + } + toggleDisplay(showItems, hideItems) { + showItems.forEach(item => { + this.inputs[item].style.display = "block"; + }); + hideItems.forEach(item => { + this.inputs[item].style.display = "none"; + }); + }; + + change(e) { + if (e == "PHYSICAL") { + this.toggleDisplay(this.physical, this.legal); + } else if (e == "LEGAL") { + this.toggleDisplay(this.legal, this.physical); + } + } +} + +document.addEventListener("DOMContentLoaded", () => { + let obj = new Changer(); + let select = document.querySelector("#id_person_type"); + select.addEventListener("change", (e) => obj.change(e.target.value)); + obj.change(select.value); +}) \ No newline at end of file diff --git a/order/resources/static/js/vite-refresh.js b/order/resources/static/js/vite-refresh.js new file mode 100644 index 0000000..019ed44 --- /dev/null +++ b/order/resources/static/js/vite-refresh.js @@ -0,0 +1,9 @@ +import RefreshRuntime from 'http://localhost:5173/@react-refresh' + +if (RefreshRuntime) { + RefreshRuntime.injectIntoGlobalHook(window) + window.$RefreshReg$ = () => { + } + window.$RefreshSig$ = () => (type) => type + window.__vite_plugin_react_preamble_installed__ = true +} \ No newline at end of file diff --git a/order/resources/static/vite/assets/appCss-w40geAFS.js b/order/resources/static/vite/assets/appCss-w40geAFS.js new file mode 100644 index 0000000..e69de29 diff --git a/order/resources/static/vite/assets/appJs-YH6iAcjX.js b/order/resources/static/vite/assets/appJs-YH6iAcjX.js new file mode 100644 index 0000000..7274c06 --- /dev/null +++ b/order/resources/static/vite/assets/appJs-YH6iAcjX.js @@ -0,0 +1,6 @@ +var Ce=!1,Me=!1,L=[],Te=-1;function zn(e){Hn(e)}function Hn(e){L.includes(e)||L.push(e),qn()}function Mt(e){let t=L.indexOf(e);t!==-1&&t>Te&&L.splice(t,1)}function qn(){!Me&&!Ce&&(Ce=!0,queueMicrotask(Wn))}function Wn(){Ce=!1,Me=!0;for(let e=0;ee.effect(t,{scheduler:n=>{Ie?zn(n):n()}}),Tt=e.raw}function _t(e){K=e}function Vn(e){let t=()=>{};return[r=>{let i=K(r);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),q(i))},i},()=>{t()}]}function It(e,t){let n=!0,r,i=K(()=>{let o=e();JSON.stringify(o),n?r=o:queueMicrotask(()=>{t(o,r),r=o}),n=!1});return()=>q(i)}function X(e,t,n={}){e.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0,composed:!0,cancelable:!0}))}function I(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>I(i,t));return}let n=!1;if(t(e,()=>n=!0),n)return;let r=e.firstElementChild;for(;r;)I(r,t),r=r.nextElementSibling}function O(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var ht=!1;function Yn(){ht&&O("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),ht=!0,document.body||O("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `