From 37f3e202cc718c1f1456ef35005900f2cf5b3d22 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 20:10:42 +0330 Subject: [PATCH 01/30] save token in swagger --- backend/core/settings/base.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/core/settings/base.py b/backend/core/settings/base.py index 695947c..f310b99 100644 --- a/backend/core/settings/base.py +++ b/backend/core/settings/base.py @@ -191,7 +191,10 @@ SPECTACULAR_SETTINGS = { 'DESCRIPTION': os.getenv("SITE_TITLE"), 'VERSION': '2.0.0', 'SERVE_INCLUDE_SCHEMA': False, - 'COMPONENT_SPLIT_REQUEST': True + 'COMPONENT_SPLIT_REQUEST': True, + "SWAGGER_UI_SETTINGS": { + "persistAuthorization": True + } } From 37982cb1a0df5482e72ab41271f4f2040c211815 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 21:09:48 +0330 Subject: [PATCH 02/30] setting clean up --- backend/.env.local | 4 +- backend/core/settings/base.py | 319 ++++++++++++++------------- backend/core/settings/production.py | 2 + backend/core/settings/unfold_conf.py | 5 +- 4 files changed, 173 insertions(+), 157 deletions(-) diff --git a/backend/.env.local b/backend/.env.local index 657f88f..e0f9789 100644 --- a/backend/.env.local +++ b/backend/.env.local @@ -28,4 +28,6 @@ REFRESH_TOKEN_LIFETIME = 5000 SMS_API_KEY = '' -VAPID_PRIVATE_KEY = 'NajogmGTsGsZ_dfURrjUpgsm5fui-s5AzruBQgMh_I4' \ No newline at end of file +VAPID_PRIVATE_KEY = 'NajogmGTsGsZ_dfURrjUpgsm5fui-s5AzruBQgMh_I4' + +OPENAI_API_KEY = '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' \ No newline at end of file diff --git a/backend/core/settings/base.py b/backend/core/settings/base.py index f310b99..96b8693 100644 --- a/backend/core/settings/base.py +++ b/backend/core/settings/base.py @@ -1,5 +1,4 @@ from dotenv import load_dotenv -# from http.cookiejar import debug from pathlib import Path from datetime import timedelta import os @@ -7,15 +6,21 @@ from django.templatetags.static import static from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ +# Load environment variables load_dotenv(".env.local") +# ============================================================================== +# General Configuration +# ============================================================================== DOMAIN = os.getenv("DOMAIN") API_DOMAIN = os.getenv("API_DOMAIN") -OPENAI_API_KEY = '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' -# TODO update telegram bot token -TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") -# TODO update email bullshit +# API Keys and Tokens +OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") +TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") +VAPID_PRIVATE_KEY = os.getenv("VAPID_PRIVATE_KEY") + +# Email Configuration EMAIL_BACKEND = os.getenv("EMAIL_BACKEND") EMAIL_HOST = os.getenv("EMAIL_HOST") EMAIL_PORT = 587 @@ -24,17 +29,16 @@ EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER") EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") DEFAULT_FROM_EMAIL = os.getenv("SECRET_KEY") +# Security and Debugging SECRET_KEY = os.getenv("SECRET_KEY") DEBUG = True BASE_DIR = Path(__file__).resolve().parent.parent.parent - -VAPID_PRIVATE_KEY = os.getenv('VAPID_PRIVATE_KEY') - -# Application definition - +# ============================================================================== +# Application Definition +# ============================================================================== INSTALLED_APPS = [ - # unfold theme + # Unfold Theme "unfold", "unfold.contrib.filters", "unfold.contrib.forms", @@ -42,37 +46,158 @@ INSTALLED_APPS = [ "unfold.contrib.import_export", "unfold.contrib.guardian", "unfold.contrib.simple_history", - # django - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # thired party apps - 'corsheaders', - 'rest_framework', - 'drf_spectacular', - 'django_cleanup.apps.CleanupConfig', - 'django_filters', - 'rest_framework_simplejwt', - 'rest_framework_simplejwt.token_blacklist', - 'rest_framework.authtoken', - 'import_export', + # Django Core + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + # Third-Party Apps + "corsheaders", + "rest_framework", + "drf_spectacular", + "django_cleanup.apps.CleanupConfig", + "django_filters", + "rest_framework_simplejwt", + "rest_framework_simplejwt.token_blacklist", + "rest_framework.authtoken", + "import_export", "django_jalali", - # custom apps - 'product', - 'account', - 'ticket', - 'chat', - 'order', - 'home', - 'blog', - + # Custom Apps + "product", + "account", + "ticket", + "chat", + "order", + "home", + "blog", ] +# ============================================================================== +# Middleware Configuration +# ============================================================================== +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "whitenoise.middleware.WhiteNoiseMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "core.urls" + +# ============================================================================== +# Template Configuration +# ============================================================================== +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [BASE_DIR / "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", + ], + }, + }, +] + +WSGI_APPLICATION = "core.wsgi.application" + +# ============================================================================== +# Authentication and Password Validation +# ============================================================================== +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + +LANGUAGE_CODE = "fa" +TIME_ZONE = "UTC" +USE_I18N = True +USE_L10N = True +USE_TZ = True + +# ============================================================================== +# Static Files Configuration +# ============================================================================== +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "custom_static"), + BASE_DIR / "core" / "static", +] + + + + +STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" +AUTH_USER_MODEL = "account.User" + +# ============================================================================== +# REST Framework Configuration +# ============================================================================== +REST_FRAMEWORK = { + # "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"], + "DEFAULT_RENDERER_CLASSES": [ + "rest_framework.renderers.JSONRenderer", + "rest_framework.renderers.BrowsableAPIRenderer", + ], + "DEFAULT_AUTHENTICATION_CLASSES": ( + "rest_framework_simplejwt.authentication.JWTAuthentication", + ), + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", + # "DEFAULT_PERMISSION_CLASSES": [ + # "rest_framework.permissions.IsAuthenticated", + # ], +} + +# ============================================================================== +# Simple JWT Configuration +# ============================================================================== +SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(days=1), + "REFRESH_TOKEN_LIFETIME": timedelta(days=7), + "ROTATE_REFRESH_TOKENS": True, + "BLACKLIST_AFTER_ROTATION": True, +} + +# ============================================================================== +# Spectacular (API Documentation) Configuration +# ============================================================================== +SPECTACULAR_SETTINGS = { + "TITLE": os.getenv("SITE_TITLE"), + "DESCRIPTION": os.getenv("SITE_TITLE"), + "VERSION": "2.0.0", + "SERVE_INCLUDE_SCHEMA": False, + "COMPONENT_SPLIT_REQUEST": True, + "SWAGGER_UI_SETTINGS": { + "persistAuthorization": True, + }, +} + +# ============================================================================== +# Persian Datetime Configuration +# ============================================================================== JALALI_SETTINGS = { - # JavaScript static files for the admin Jalali date widget "ADMIN_JS_STATIC_FILES": [ "admin/jquery.ui.datepicker.jalali/scripts/jquery-1.10.2.min.js", "admin/jquery.ui.datepicker.jalali/scripts/jquery.ui.core.js", @@ -81,126 +206,10 @@ JALALI_SETTINGS = { "admin/jquery.ui.datepicker.jalali/scripts/jquery.ui.datepicker-cc-fa.js", "admin/main.js", ], - # CSS static files for the admin Jalali date widget "ADMIN_CSS_STATIC_FILES": { "all": [ "admin/jquery.ui.datepicker.jalali/themes/base/jquery-ui.min.css", "admin/css/main.css", ] }, -} - - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - "whitenoise.middleware.WhiteNoiseMiddleware", - 'django.contrib.sessions.middleware.SessionMiddleware', - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'core.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [BASE_DIR / "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', - ], - }, - }, -] - -WSGI_APPLICATION = 'core.wsgi.application' - - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -LANGUAGE_CODE = 'fa' - -TIME_ZONE = 'UTC' - -USE_I18N = True -USE_L10N = True -USE_TZ = True - - - -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'custom_static'), - BASE_DIR / "core" / "static" -] - -STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" - -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - -AUTH_USER_MODEL = 'account.User' - - -REST_FRAMEWORK = { - # 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], - 'DEFAULT_RENDERER_CLASSES': [ - 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.BrowsableAPIRenderer', - - ], - 'DEFAULT_AUTHENTICATION_CLASSES': ( - - 'rest_framework_simplejwt.authentication.JWTAuthentication', - - ), - 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', - # 'DEFAULT_PERMISSION_CLASSES': [ - # 'rest_framework.permissions.IsAuthenticated', - # ], -} - -SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(days=1), - 'REFRESH_TOKEN_LIFETIME': timedelta(days=7), - 'ROTATE_REFRESH_TOKENS': True, - 'BLACKLIST_AFTER_ROTATION': True, -} - -SPECTACULAR_SETTINGS = { - 'TITLE': os.getenv("SITE_TITLE"), - 'DESCRIPTION': os.getenv("SITE_TITLE"), - 'VERSION': '2.0.0', - 'SERVE_INCLUDE_SCHEMA': False, - 'COMPONENT_SPLIT_REQUEST': True, - "SWAGGER_UI_SETTINGS": { - "persistAuthorization": True - } -} - - - - -def environment_callback(request): - return ["نسخه ی توسعه", "success"] - - +} \ No newline at end of file diff --git a/backend/core/settings/production.py b/backend/core/settings/production.py index 4ce04ef..2a5497f 100644 --- a/backend/core/settings/production.py +++ b/backend/core/settings/production.py @@ -1,5 +1,7 @@ from .base import * from .unfold_conf import * + + ALLOWED_HOSTS = ['127.0.0.1', 'localhost', DOMAIN, API_DOMAIN] CSRF_TRUSTED_ORIGINS = [ f"https://{DOMAIN}", diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py index a4ad30f..045106b 100644 --- a/backend/core/settings/unfold_conf.py +++ b/backend/core/settings/unfold_conf.py @@ -264,4 +264,7 @@ UNFOLD = { ], }, -} \ No newline at end of file +} + +def environment_callback(request): + return ["نسخه ی توسعه", "success"] \ No newline at end of file From 7531302b49936ce8effebaf3336e4206a21bb167 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 22:13:56 +0330 Subject: [PATCH 03/30] aw3 file server added to backend --- backend/core/settings/base.py | 21 ++++++++++++++++++- backend/core/settings/production.py | 11 +++++++++- backend/core/storages.py | 6 ++++++ backend/requirements.txt | 32 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 backend/core/storages.py diff --git a/backend/core/settings/base.py b/backend/core/settings/base.py index 96b8693..c1d752b 100644 --- a/backend/core/settings/base.py +++ b/backend/core/settings/base.py @@ -54,6 +54,7 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", # Third-Party Apps + "storages", "corsheaders", "rest_framework", "drf_spectacular", @@ -212,4 +213,22 @@ JALALI_SETTINGS = { "admin/css/main.css", ] }, -} \ No newline at end of file +} + + +# ============================================================================== +# AWS S3 setting for production +# ============================================================================== +AWS_ACCESS_KEY_ID = 'mtiSN2JWjWgyfr2u' +AWS_SECRET_ACCESS_KEY = 'ZGmOM6ekLJEswJS1kOLp49B8DQ3GT0HZ' +AWS_STORAGE_BUCKET_NAME = 'c262408' +AWS_S3_ENDPOINT_URL = 'https://parspack.net' +AWS_S3_REGION_NAME = 'default' +AWS_S3_SIGNATURE_VERSION = 's3' +AWS_S3_ADDRESSING_STYLE = 'virtual' +AWS_QUERYSTRING_AUTH = True +AWS_DEFAULT_ACL = None +AWS_S3_OBJECT_PARAMETERS = { + 'CacheControl': 'max-age=86400', +} + diff --git a/backend/core/settings/production.py b/backend/core/settings/production.py index 2a5497f..3ec44aa 100644 --- a/backend/core/settings/production.py +++ b/backend/core/settings/production.py @@ -33,7 +33,16 @@ DATABASES = { } } -MEDIA_URL = '/shop_media/' +STORAGES = { + "default": { + "BACKEND": 'core.storages.MediaStorage', + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", + }, +} + +MEDIA_URL = 'https://c262408.parspack.net/' MEDIA_ROOT = '/app/media' STATIC_URL = '/shop_static/' diff --git a/backend/core/storages.py b/backend/core/storages.py new file mode 100644 index 0000000..766fd23 --- /dev/null +++ b/backend/core/storages.py @@ -0,0 +1,6 @@ +from storages.backends.s3boto3 import S3Boto3Storage + + +class MediaStorage(S3Boto3Storage): + location = 'media' + default_acl = 'private' \ No newline at end of file diff --git a/backend/requirements.txt b/backend/requirements.txt index ca6be94..83cdbca 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -5,22 +5,33 @@ annotated-types==0.7.0 anyio==4.6.0 asgiref==3.8.1 attrs==24.2.0 +az-iranian-bank-gateways==2.0.5 +beautifulsoup4==4.12.3 +boto3==1.36.26 +botocore==1.36.26 branca==0.8.1 certifi==2024.8.30 cffi==1.17.1 charset-normalizer==3.3.2 +colorama==0.4.6 cryptography==44.0.1 defusedxml==0.8.0rc2 diff-match-patch==20230430 distro==1.9.0 Django==5.1.2 +django-admin-interface==0.28.5 +django-admin-persian-fonts==0.2 django-cleanup==8.1.0 +django-colorfield==0.11.0 django-cors-headers==4.4.0 +django-cron==0.6.0 django-dbbackup==4.2.1 +django-dirtyfields==1.9.3 django-filter==24.3 django-import-export==4.1.1 django-iranian-cities==1.0.2 django-jalali==7.3.0 +django-storages==1.14.5 django-unfold==0.48.0 djangorestframework==3.15.2 djangorestframework-simplejwt==5.3.1 @@ -28,6 +39,7 @@ djoser==2.3.1 dnspython==2.7.0 drf-spectacular==0.27.2 email_validator==2.2.0 +et-xmlfile==1.1.0 factory_boy==3.3.1 Faker==28.4.1 folium==0.19.4 @@ -43,29 +55,40 @@ httpcore==1.0.5 httpx==0.27.2 idna==3.10 inflection==0.5.1 +isodate==0.6.1 jalali_core==1.0.0 jdatetime==5.0.0 Jinja2==3.1.5 jiter==0.8.2 +jmespath==1.0.1 jsonschema==4.23.0 jsonschema-specifications==2024.10.1 +lxml==5.2.2 +MarkupPy==1.14 MarkupSafe==3.0.2 maxminddb==2.6.2 multidict==6.1.0 numpy==2.2.3 oauthlib==3.2.2 +odfpy==1.4.1 openai==1.58.1 +openpyxl==3.1.2 pillow==10.4.0 +platformdirs==4.2.2 +propcache==0.2.0 psutil==6.0.0 psycopg2-binary==2.9.10 py-vapid==1.9.2 pycparser==2.22 +pycryptodome==3.20.0 pydantic==2.10.6 pydantic_core==2.27.2 PyJWT==2.10.1 pyTelegramBotAPI==4.23.0 python-dateutil==2.9.0.post0 +python-decouple==3.8 python-dotenv==1.0.1 +python-slugify==8.0.4 python-telegram-bot==21.6 python3-openid==3.2.0 pytz==2024.2 @@ -73,20 +96,29 @@ pywebpush==2.0.3 PyYAML==6.0.2 referencing==0.35.1 requests==2.32.3 +requests-file==2.1.0 requests-oauthlib==2.0.0 +requests-toolbelt==1.0.0 rpds-py==0.20.0 +s3transfer==0.11.2 setuptools==75.1.0 six==1.16.0 sniffio==1.3.1 social-auth-app-django==5.4.2 social-auth-core==4.5.4 +soupsieve==2.5 sqlparse==0.5.1 tablib==3.5.0 +telebot==0.0.5 +text-unidecode==1.3 tqdm==4.67.1 typing_extensions==4.12.2 tzdata==2024.1 uritemplate==4.1.1 urllib3==2.2.3 whitenoise==6.7.0 +xlrd==2.0.1 +xlwt==1.3.0 xyzservices==2025.1.0 yarl==1.11.1 +zeep==4.2.1 From 0180f528e28af4d5fdf00a012b9fc60226d1000d Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 23:08:36 +0330 Subject: [PATCH 04/30] auto backup and send via telegram --- backup/backup.sh | 30 ++++++++++++++++++++++++++++++ backup/crontab | 1 + backup/dockerfile | 6 ++++++ docker-compose.yml | 20 ++++++++++++++++++-- 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 backup/backup.sh create mode 100644 backup/crontab create mode 100644 backup/dockerfile diff --git a/backup/backup.sh b/backup/backup.sh new file mode 100644 index 0000000..aa2bc49 --- /dev/null +++ b/backup/backup.sh @@ -0,0 +1,30 @@ +#!/bin/sh +echo 'started the backup' +# Telegram API URL +TELEGRAM_API="https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" + +# Generate timestamp +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="backup_${TIMESTAMP}.sql" +ZIP_FILE="backup_${TIMESTAMP}.zip" + +# Create backup +pg_dump -h $PG_HOST -p $PG_PORT -U $PG_USER -d $PG_DATABASE > /backups/$BACKUP_FILE + +# Check if backup succeeded +if [ $? -ne 0 ]; then + echo "Backup failed!" + exit 1 +fi + +# Zip the backup +zip -j /backups/$ZIP_FILE /backups/$BACKUP_FILE + +# Send to Telegram +curl -F chat_id=$TELEGRAM_CHAT_ID \ + -F document=@/backups/$ZIP_FILE \ + $TELEGRAM_API + +# Cleanup (keep last 3 backups) +ls -t /backups/*.zip | tail -n +4 | xargs rm -f +ls -t /backups/*.sql | tail -n +4 | xargs rm -f \ No newline at end of file diff --git a/backup/crontab b/backup/crontab new file mode 100644 index 0000000..5c39650 --- /dev/null +++ b/backup/crontab @@ -0,0 +1 @@ +* * * * * /app/backup.sh \ No newline at end of file diff --git a/backup/dockerfile b/backup/dockerfile new file mode 100644 index 0000000..701f401 --- /dev/null +++ b/backup/dockerfile @@ -0,0 +1,6 @@ +FROM alpine:3.19 +RUN apk add --no-cache postgresql-client curl zip tzdata +WORKDIR /app +COPY backup.sh . +RUN chmod +x backup.sh +CMD ["/app/backup.sh"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 6a21034..980df82 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,11 +42,27 @@ services: networks: - default - + db-backup: + build: + context: ./backup + depends_on: + - db + environment: + - PG_HOST=db + - PG_PORT=5432 + - PG_DATABASE=hshop + - PG_USER=byeto + - PG_PASSWORD=vuhbyq-cypMu0-sirbon + - TELEGRAM_BOT_TOKEN='7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g' + - TELEGRAM_CHAT_ID=1198382521 + volumes: + - backups:/backups + networks: + - default volumes: postgres_data: media_data: - + backups: networks: default: \ No newline at end of file From 03f4158800d390d3f83f5386ea3eeab64a40340b Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 23:11:57 +0330 Subject: [PATCH 05/30] fix docker compose up --- docker-compose.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 980df82..96a262d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,21 +44,21 @@ services: db-backup: build: - context: ./backup + context: ./backup depends_on: - - db + - db environment: - - PG_HOST=db - - PG_PORT=5432 - - PG_DATABASE=hshop - - PG_USER=byeto - - PG_PASSWORD=vuhbyq-cypMu0-sirbon - - TELEGRAM_BOT_TOKEN='7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g' - - TELEGRAM_CHAT_ID=1198382521 + - PG_HOST=db + - PG_PORT=5432 + - PG_DATABASE=hshop + - PG_USER=byeto + - PG_PASSWORD=vuhbyq-cypMu0-sirbon + - TELEGRAM_BOT_TOKEN='7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g' + - TELEGRAM_CHAT_ID=1198382521 volumes: - - backups:/backups + - backups:/backups networks: - - default + - default volumes: postgres_data: From 464cb1f5506e7dfaabb676ca3f549dddb44009c6 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 23:24:06 +0330 Subject: [PATCH 06/30] debug database backup --- backup/backup.sh | 15 +++++---------- docker-compose.yml | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/backup/backup.sh b/backup/backup.sh index aa2bc49..99b6963 100644 --- a/backup/backup.sh +++ b/backup/backup.sh @@ -1,30 +1,25 @@ #!/bin/sh echo 'started the backup' -# Telegram API URL -TELEGRAM_API="https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" +export PGPASSWORD=$PG_PASSWORD -# Generate timestamp + +TELEGRAM_API="https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="backup_${TIMESTAMP}.sql" ZIP_FILE="backup_${TIMESTAMP}.zip" -# Create backup -pg_dump -h $PG_HOST -p $PG_PORT -U $PG_USER -d $PG_DATABASE > /backups/$BACKUP_FILE -# Check if backup succeeded +pg_dump -h $PG_HOST -p $PG_PORT -U $PG_USER -d $PG_DATABASE -w > /backups/$BACKUP_FILE + if [ $? -ne 0 ]; then echo "Backup failed!" exit 1 fi -# Zip the backup zip -j /backups/$ZIP_FILE /backups/$BACKUP_FILE - -# Send to Telegram curl -F chat_id=$TELEGRAM_CHAT_ID \ -F document=@/backups/$ZIP_FILE \ $TELEGRAM_API -# Cleanup (keep last 3 backups) ls -t /backups/*.zip | tail -n +4 | xargs rm -f ls -t /backups/*.sql | tail -n +4 | xargs rm -f \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 96a262d..edfab7e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,8 +52,8 @@ services: - PG_PORT=5432 - PG_DATABASE=hshop - PG_USER=byeto - - PG_PASSWORD=vuhbyq-cypMu0-sirbon - - TELEGRAM_BOT_TOKEN='7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g' + - PG_PASSWORD=vuhbyq-cypMu0-sirbon # Remove single quotes here + - TELEGRAM_BOT_TOKEN=7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g - TELEGRAM_CHAT_ID=1198382521 volumes: - backups:/backups From 6c68d3f4b8206a811bc67970c8ecf537e83c45b7 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 24 Feb 2025 23:35:42 +0330 Subject: [PATCH 07/30] docker sculated time --- backup/backup.sh | 2 ++ backup/crontab | 7 ++++++- backup/dockerfile | 16 +++++++++++++--- docker-compose.yml | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/backup/backup.sh b/backup/backup.sh index 99b6963..8ad0be7 100644 --- a/backup/backup.sh +++ b/backup/backup.sh @@ -1,4 +1,6 @@ #!/bin/sh +. /etc/profile +echo "Cron job triggered at $(date)" >> /var/log/cron/cron.log echo 'started the backup' export PGPASSWORD=$PG_PASSWORD diff --git a/backup/crontab b/backup/crontab index 5c39650..11df74a 100644 --- a/backup/crontab +++ b/backup/crontab @@ -1 +1,6 @@ -* * * * * /app/backup.sh \ No newline at end of file +# Add this line for environment variables +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# Schedule (runs every minute for testing) +* * * * * /app/backup.sh >> /var/log/cron/cron.log 2>&1 \ No newline at end of file diff --git a/backup/dockerfile b/backup/dockerfile index 701f401..391b3d5 100644 --- a/backup/dockerfile +++ b/backup/dockerfile @@ -1,6 +1,16 @@ FROM alpine:3.19 -RUN apk add --no-cache postgresql-client curl zip tzdata + +RUN apk add --no-cache postgresql-client curl zip tzdata cron +RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime +RUN mkdir -p /var/log/cron + + WORKDIR /app COPY backup.sh . -RUN chmod +x backup.sh -CMD ["/app/backup.sh"] \ No newline at end of file +COPY crontab /etc/crontabs/root + +RUN chmod +x backup.sh && \ + chmod 0644 /etc/crontabs/root && \ + touch /var/log/cron/cron.log + +CMD ["sh", "-c", "crond -l 8 -L /var/log/cron/cron.log -f"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index edfab7e..ff1d39c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,7 +52,7 @@ services: - PG_PORT=5432 - PG_DATABASE=hshop - PG_USER=byeto - - PG_PASSWORD=vuhbyq-cypMu0-sirbon # Remove single quotes here + - PG_PASSWORD=vuhbyq-cypMu0-sirbon - TELEGRAM_BOT_TOKEN=7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g - TELEGRAM_CHAT_ID=1198382521 volumes: From 6649f5eecbc7f6dadc2787ac6a4806355de835e6 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:00:29 +0330 Subject: [PATCH 08/30] update backup cron bug --- backup/backup.sh | 20 ++++++++++++++------ backup/crontab | 5 ----- backup/dockerfile | 12 ++++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/backup/backup.sh b/backup/backup.sh index 8ad0be7..dd93e9a 100644 --- a/backup/backup.sh +++ b/backup/backup.sh @@ -1,9 +1,16 @@ #!/bin/sh -. /etc/profile -echo "Cron job triggered at $(date)" >> /var/log/cron/cron.log -echo 'started the backup' -export PGPASSWORD=$PG_PASSWORD +# Load environment variables +. /etc/profile + +# Debugging output +echo "Cron environment:" >> /var/log/cron/cron.log +env >> /var/log/cron/cron.log + + +echo "Starting backup at $(date)" >> /var/log/cron/cron.log + +export PGPASSWORD=$PG_PASSWORD TELEGRAM_API="https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" TIMESTAMP=$(date +%Y%m%d_%H%M%S) @@ -14,7 +21,7 @@ ZIP_FILE="backup_${TIMESTAMP}.zip" pg_dump -h $PG_HOST -p $PG_PORT -U $PG_USER -d $PG_DATABASE -w > /backups/$BACKUP_FILE if [ $? -ne 0 ]; then - echo "Backup failed!" + echo "Backup failed!" >> /var/log/cron/cron.log exit 1 fi @@ -24,4 +31,5 @@ curl -F chat_id=$TELEGRAM_CHAT_ID \ $TELEGRAM_API ls -t /backups/*.zip | tail -n +4 | xargs rm -f -ls -t /backups/*.sql | tail -n +4 | xargs rm -f \ No newline at end of file +ls -t /backups/*.sql | tail -n +4 | xargs rm -f +echo "Backup completed at $(date)" >> /var/log/cron/cron.log \ No newline at end of file diff --git a/backup/crontab b/backup/crontab index 11df74a..d47cb15 100644 --- a/backup/crontab +++ b/backup/crontab @@ -1,6 +1 @@ -# Add this line for environment variables -SHELL=/bin/sh -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -# Schedule (runs every minute for testing) * * * * * /app/backup.sh >> /var/log/cron/cron.log 2>&1 \ No newline at end of file diff --git a/backup/dockerfile b/backup/dockerfile index 391b3d5..438a3c5 100644 --- a/backup/dockerfile +++ b/backup/dockerfile @@ -1,16 +1,20 @@ FROM alpine:3.19 RUN apk add --no-cache postgresql-client curl zip tzdata cron -RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime -RUN mkdir -p /var/log/cron +RUN mkdir -p /app /var/log/cron WORKDIR /app COPY backup.sh . COPY crontab /etc/crontabs/root RUN chmod +x backup.sh && \ chmod 0644 /etc/crontabs/root && \ - touch /var/log/cron/cron.log + touch /var/log/cron/cron.log && \ + chmod 666 /var/log/cron/cron.log -CMD ["sh", "-c", "crond -l 8 -L /var/log/cron/cron.log -f"] \ No newline at end of file + +RUN printenv | grep -E 'PG_|TELEGRAM_' >> /etc/environment + + +CMD ["sh", "-c", "crond -f -l 0 -L /var/log/cron/cron.log"] \ No newline at end of file From 9e6db820f0660026b688f467de9db12f178e6fa8 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:09:48 +0330 Subject: [PATCH 09/30] dockerfile update test --- backup/dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup/dockerfile b/backup/dockerfile index 438a3c5..4790e11 100644 --- a/backup/dockerfile +++ b/backup/dockerfile @@ -17,4 +17,4 @@ RUN chmod +x backup.sh && \ RUN printenv | grep -E 'PG_|TELEGRAM_' >> /etc/environment -CMD ["sh", "-c", "crond -f -l 0 -L /var/log/cron/cron.log"] \ No newline at end of file +CMD ["crond", "-f", "-l", "8", "-L", "/var/log/cron/cron.log"] \ No newline at end of file From eec07de14e574221422bf6b7114694700b7e6b6f Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:16:26 +0330 Subject: [PATCH 10/30] dokcer test bullshit --- backup/dockerfile | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/backup/dockerfile b/backup/dockerfile index 4790e11..cd97560 100644 --- a/backup/dockerfile +++ b/backup/dockerfile @@ -1,20 +1,15 @@ FROM alpine:3.19 -RUN apk add --no-cache postgresql-client curl zip tzdata cron +RUN apk add --no-cache postgresql-client curl zip tzdata dcron +RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime +RUN mkdir -p /var/log/cron /backups - -RUN mkdir -p /app /var/log/cron WORKDIR /app COPY backup.sh . COPY crontab /etc/crontabs/root RUN chmod +x backup.sh && \ chmod 0644 /etc/crontabs/root && \ - touch /var/log/cron/cron.log && \ - chmod 666 /var/log/cron/cron.log + touch /var/log/cron/cron.log - -RUN printenv | grep -E 'PG_|TELEGRAM_' >> /etc/environment - - -CMD ["crond", "-f", "-l", "8", "-L", "/var/log/cron/cron.log"] \ No newline at end of file +CMD ["crond", "-f", "-L", "/var/log/cron/cron.log"] \ No newline at end of file From 523685c3bc3ac1a0e8fd59d2c242aab0a4efc377 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:19:41 +0330 Subject: [PATCH 11/30] i dont know --- docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index ff1d39c..db34975 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,6 +59,8 @@ services: - backups:/backups networks: - default + cap_add: + - SYS_ADMIN volumes: postgres_data: From 8271429b031fd75510c9113ed08f41656ddb24aa Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:22:40 +0330 Subject: [PATCH 12/30] test --- backup/dockerfile | 4 ++-- docker-compose.yml | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/backup/dockerfile b/backup/dockerfile index cd97560..08b66d8 100644 --- a/backup/dockerfile +++ b/backup/dockerfile @@ -1,6 +1,6 @@ FROM alpine:3.19 -RUN apk add --no-cache postgresql-client curl zip tzdata dcron +RUN apk add --no-cache postgresql-client curl zip tzdata RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime RUN mkdir -p /var/log/cron /backups @@ -12,4 +12,4 @@ RUN chmod +x backup.sh && \ chmod 0644 /etc/crontabs/root && \ touch /var/log/cron/cron.log -CMD ["crond", "-f", "-L", "/var/log/cron/cron.log"] \ No newline at end of file +CMD ["busybox", "crond", "-f", "-L", "/var/log/cron/cron.log"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index db34975..ff1d39c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,8 +59,6 @@ services: - backups:/backups networks: - default - cap_add: - - SYS_ADMIN volumes: postgres_data: From 1246a3a8bb615fc8ba29d8589249a6e1d90cc7ab Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:36:12 +0330 Subject: [PATCH 13/30] send every 3 am and send to amins --- backup/backup.sh | 8 ++++++-- backup/crontab | 2 +- docker-compose.yml | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backup/backup.sh b/backup/backup.sh index dd93e9a..4e0a1cb 100644 --- a/backup/backup.sh +++ b/backup/backup.sh @@ -14,8 +14,8 @@ export PGPASSWORD=$PG_PASSWORD TELEGRAM_API="https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" TIMESTAMP=$(date +%Y%m%d_%H%M%S) -BACKUP_FILE="backup_${TIMESTAMP}.sql" -ZIP_FILE="backup_${TIMESTAMP}.zip" +BACKUP_FILE="backup_heymlz_shop${TIMESTAMP}.sql" +ZIP_FILE="backup_heymlz_shop${TIMESTAMP}.zip" pg_dump -h $PG_HOST -p $PG_PORT -U $PG_USER -d $PG_DATABASE -w > /backups/$BACKUP_FILE @@ -30,6 +30,10 @@ curl -F chat_id=$TELEGRAM_CHAT_ID \ -F document=@/backups/$ZIP_FILE \ $TELEGRAM_API +curl -F chat_id=$TELEGRAM_CHAT_ID2 \ + -F document=@/backups/$ZIP_FILE \ + $TELEGRAM_API + ls -t /backups/*.zip | tail -n +4 | xargs rm -f ls -t /backups/*.sql | tail -n +4 | xargs rm -f echo "Backup completed at $(date)" >> /var/log/cron/cron.log \ No newline at end of file diff --git a/backup/crontab b/backup/crontab index d47cb15..2341de2 100644 --- a/backup/crontab +++ b/backup/crontab @@ -1 +1 @@ -* * * * * /app/backup.sh >> /var/log/cron/cron.log 2>&1 \ No newline at end of file +0 3 * * * /app/backup.sh >> /var/log/cron/cron.log 2>&1 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index ff1d39c..eded502 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -55,6 +55,7 @@ services: - PG_PASSWORD=vuhbyq-cypMu0-sirbon - TELEGRAM_BOT_TOKEN=7068288679:AAGecMnyt9A6R78OQu8nQeISMK1LepX718g - TELEGRAM_CHAT_ID=1198382521 + - TELEGRAM_CHAT_ID2=5115366609 volumes: - backups:/backups networks: From 880ab60facfd5b8ddc233b9324a21631ca3ff631 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 00:54:50 +0330 Subject: [PATCH 14/30] order list view and serilaizer --- backend/order/models.py | 20 +++++++++++--------- backend/order/serializers.py | 10 ++++++++-- backend/order/urls.py | 3 ++- backend/order/views.py | 19 ++++++++++++------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/backend/order/models.py b/backend/order/models.py index 570351b..3f37b5b 100644 --- a/backend/order/models.py +++ b/backend/order/models.py @@ -59,21 +59,23 @@ class OrderModel(models.Model): print('didnt send') super().save(*args, **kwargs) - def total_with_discount(self): - total_with_item_discount = sum(item.total_with_discount() for item in self.items.all()) - if self.discount_code: - if not self.discount_code.is_valid(): - raise DiscountNotAvailableError('این کد تخفیف دیگر معتبر نیست') - discount_percent = self.discount_code.percent - return total_with_item_discount * ((100 - discount_percent) / 100) - return total_with_item_discount + def discount(self): + pass + # total_with_item_discount = sum(item.total_with_discount() for item in self.items.all()) + # if self.discount_code: + # if not self.discount_code.is_valid(): + # raise DiscountNotAvailableError('این کد تخفیف دیگر معتبر نیست') + # discount_percent = self.discount_code.percent + # return total_with_item_discount * ((100 - discount_percent) / 100) + # return total_with_item_discount def tax(self): return self.total_without_tax() * 0.2 def total(self): - return self.total_with_discount() + self.tax() + pass + # return self.total_with_discount() + self.tax() def remove_order_item(self, item_pk, quantity): pass diff --git a/backend/order/serializers.py b/backend/order/serializers.py index 093c002..880b064 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -8,8 +8,14 @@ class OrderItemSerailzier(serializers.ModelSerializer): fields = "__all__" read_only_fields = ('order', 'product') -class OrderModelSerializer(serializers.ModelSerializer): +class CartSerializer(serializers.ModelSerializer): items = OrderItemSerailzier(many=True) class Meta: model = OrderModel - fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code', 'items'] \ No newline at end of file + fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code', 'items'] + + +class OrderSerializer(serializers.ModelSerializer): + class Meta: + model = OrderModel + fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code',] \ No newline at end of file diff --git a/backend/order/urls.py b/backend/order/urls.py index a4d4dbd..325e1a5 100644 --- a/backend/order/urls.py +++ b/backend/order/urls.py @@ -1,9 +1,10 @@ from django.conf.urls.static import static from django.contrib import admin from django.urls import path, include -from .views import CartItemViews, CartView +from .views import CartItemViews, CartView, OrderlistView urlpatterns = [ + path('list', OrderlistView.as_view(), name='order-list'), path('cart', CartView.as_view()), path('cart/item/', CartItemViews.as_view(), name='change-item-cart'), # path('payment', CartView.as_view()), diff --git a/backend/order/views.py b/backend/order/views.py index 7f5971c..bb21f5a 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -4,7 +4,7 @@ from rest_framework.views import APIView, Response from django.shortcuts import get_object_or_404 from product.models import ProductVariant from rest_framework.permissions import IsAuthenticated -from .serializers import OrderItemSerailzier, OrderModelSerializer +from .serializers import * # from cart.models import from rest_framework import status from .models import OrderItemModel, OrderModel @@ -53,11 +53,6 @@ class CartItemViews(APIView): user=request.user, status='CART' ) - # order_item, created = OrderItemModel.objects.get_or_create( - # order=cart_order, - # product=product_variant, - # defaults={'quantity': request.data.get('quantity', 1)} - # ) order_item = get_object_or_404(OrderItemModel, order=cart_order, product=product_variant) order_item.delete() return Response({'detail': f'محصول {product_variant.product.name} از سبد خرید پاک شد'}, status=status.HTTP_204_NO_CONTENT) @@ -66,9 +61,19 @@ class CartItemViews(APIView): class CartView(APIView): permission_classes = [IsAuthenticated] - serializer_class = OrderModelSerializer + serializer_class = CartSerializer def get(self, request): user = request.user cart_instance, created = OrderModel.objects.get_or_create(user=user, status='CART') cart_ser = self.serializer_class(instance=cart_instance, context={'request': request}) return Response(cart_ser.data, status=status.HTTP_200_OK) + + +class OrderlistView(APIView): + permission_classes = [IsAuthenticated] + serializer_class = OrderSerializer + def get(self, request): + user = request.user + orders = OrderModel.objects.filter(user=user).exclude(status="CART") + orders_ser = self.serializer_class(instance=orders, many=True, context={'request': request}) + return Response(orders_ser.data, status=status.HTTP_200_OK) \ No newline at end of file From cda862111aa9a91d3b2fae6a847be39903a71849 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 01:01:05 +0330 Subject: [PATCH 15/30] test push again --- backend/order/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/order/views.py b/backend/order/views.py index bb21f5a..a49d4ee 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -24,6 +24,7 @@ pay + class CartItemViews(APIView): permission_classes = [IsAuthenticated] serializer_class = OrderItemSerailzier From 4cbd1493292282a8ea41313215072bc7990a11f9 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Tue, 25 Feb 2025 01:07:11 +0330 Subject: [PATCH 16/30] update --- backend/order/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/order/views.py b/backend/order/views.py index a49d4ee..bb21f5a 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -24,7 +24,6 @@ pay - class CartItemViews(APIView): permission_classes = [IsAuthenticated] serializer_class = OrderItemSerailzier From 31655aeaa9ca5a0c808993ba2e7d84c8abb63731 Mon Sep 17 00:00:00 2001 From: Parsa Nazer <129178874+Greenstorm911@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:24:01 +0330 Subject: [PATCH 17/30] Order count and cover --- backend/order/serializers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/order/serializers.py b/backend/order/serializers.py index 880b064..aee7c89 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -16,6 +16,12 @@ class CartSerializer(serializers.ModelSerializer): class OrderSerializer(serializers.ModelSerializer): + count = serializers.SerializerMethodField() + image = serializers.SerializerMethodField() class Meta: model = OrderModel - fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code',] \ No newline at end of file + fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code', "image", "count"] + def get_count(self, obj): + return obj.items.all().count() + def get_image(self, obj): + return "this is image url place holder mamaliz" \ No newline at end of file From e5e06a5795f2d5e519d409024ffcd1721428ead9 Mon Sep 17 00:00:00 2001 From: Parsa Nazer <129178874+Greenstorm911@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:33:42 +0330 Subject: [PATCH 18/30] Image list place holder and id order list --- backend/order/serializers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/order/serializers.py b/backend/order/serializers.py index aee7c89..5950648 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -17,11 +17,11 @@ class CartSerializer(serializers.ModelSerializer): class OrderSerializer(serializers.ModelSerializer): count = serializers.SerializerMethodField() - image = serializers.SerializerMethodField() + images = serializers.SerializerMethodField() class Meta: model = OrderModel - fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code', "image", "count"] + fields = ['address', 'created_at', 'is_paid', 'status', 'discount_code', "images", "count", "id"] def get_count(self, obj): return obj.items.all().count() - def get_image(self, obj): - return "this is image url place holder mamaliz" \ No newline at end of file + def get_images(self, obj): + return ["a" , "b" , "c"] \ No newline at end of file From 640a8873ed63a9cda28391ccad254d217b878dc7 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Wed, 26 Feb 2025 19:46:15 +0330 Subject: [PATCH 19/30] comment price filter --- backend/product/views.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/product/views.py b/backend/product/views.py index 68e06e8..6606516 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -170,14 +170,14 @@ class AllProductsView(APIView): if search_query: products = products.filter(Q(name__icontains=search_query) | Q(description__icontains=search_query)) - # Price filters - price_gte = request.query_params.get('price_gte', None) - price_lte = request.query_params.get('price_lte', None) + # # Price filters + # price_gte = request.query_params.get('price_gte', None) + # price_lte = request.query_params.get('price_lte', None) - if price_gte: - products = products.filter(variants__min_price__gte=price_gte) - if price_lte: - products = products.filter(variants__min_price__lte=price_lte) + # if price_gte: + # products = products.filter(variants__min_price__gte=price_gte) + # if price_lte: + # products = products.filter(variants__min_price__lte=price_lte) # Sorting sort_by = request.query_params.get('sort', None) From 8ef2560ecdbe9a0c82c42445c170845886e4eab9 Mon Sep 17 00:00:00 2001 From: marzban-dev Date: Wed, 26 Feb 2025 20:58:47 +0330 Subject: [PATCH 20/30] Render colors --- frontend/components/global/product-detail/ProductsSlider.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/global/product-detail/ProductsSlider.vue b/frontend/components/global/product-detail/ProductsSlider.vue index dea310e..a7df480 100644 --- a/frontend/components/global/product-detail/ProductsSlider.vue +++ b/frontend/components/global/product-detail/ProductsSlider.vue @@ -92,7 +92,7 @@ const onSwiper = (swiper: SwiperClass) => { brand="برند محصول" :title="product.name" :picture="product.variants[0].images[0].image" - :colors="product.variants.map(v => v.color)" + :colors="product.colors" :price="product.variants[0].price" :rate="product.rating" :dark-layer="true" From e4c4b9178d92448816ff5840a39003e8996c8fe4 Mon Sep 17 00:00:00 2001 From: marzban-dev Date: Wed, 26 Feb 2025 20:58:52 +0330 Subject: [PATCH 21/30] Updated --- frontend/components/global/ColorCircle.vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/components/global/ColorCircle.vue b/frontend/components/global/ColorCircle.vue index 3db00be..0d3c2df 100644 --- a/frontend/components/global/ColorCircle.vue +++ b/frontend/components/global/ColorCircle.vue @@ -3,18 +3,21 @@ // types type Props = { + selectable?: boolean, selected?: boolean; } // props -defineProps(); +withDefaults(defineProps(), { + selectable: false +}); \ No newline at end of file From d47ae13dc0c522ca5f239e59e2f086ed96de1740 Mon Sep 17 00:00:00 2001 From: marzban-dev Date: Wed, 26 Feb 2025 20:59:09 +0330 Subject: [PATCH 22/30] Complete loading overlay statement --- frontend/components/global/LoadingOverlay.vue | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/frontend/components/global/LoadingOverlay.vue b/frontend/components/global/LoadingOverlay.vue index 6329eca..7b22a94 100644 --- a/frontend/components/global/LoadingOverlay.vue +++ b/frontend/components/global/LoadingOverlay.vue @@ -1,33 +1,54 @@