""" Django settings for backend project. Generated by 'django-admin startproject' using Django 5.0.4. For more information on this file, see https://docs.djangoproject.com/en/5.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/5.0/ref/settings/ """ import os from pathlib import Path from django.templatetags.static import static from django.urls import reverse_lazy import environ from django.utils.translation import gettext_lazy as _ env = environ.Env( # set casting, default value # DEBUG=(bool, False) ) # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent.parent environ.Env.read_env(os.path.join(BASE_DIR, '.env')) ALLOWED_HOSTS = env('DJANGO_ALLOWED_HOSTS').split(',') # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-7=3it+m^28^+0c1*9-*c*6g3ej63sz(97rq1^mp=!6e(mhmysh' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True X_FRAME_OPTIONS = 'SAMEORIGIN' LOCAL_APPS = [ 'apps.account.apps.AccountConfig', 'apps.api.apps.ApiConfig', 'apps.course.apps.CourseConfig', 'apps.chat.apps.ChatConfig', 'apps.quiz.apps.QuizConfig', 'apps.transaction.apps.TransactionConfig', 'apps.certificate.apps.CertificateConfig', 'apps.hadis.apps.HadisConfig', 'apps.library.apps.LibraryConfig', 'apps.video.apps.VideoConfig', 'apps.podcast.apps.PodcastConfig', 'apps.bookmark.apps.BookmarkConfig', 'apps.article.apps.ArticleConfig', 'apps.dobodbi_calendar.apps.DobodbiCalendarConfig', 'dynamic_preferences', ] THIRD_PARTY_APPS = [ 'rest_framework', 'rest_framework.authtoken', 'drf_yasg', 'rosetta', 'easy_thumbnails', 'phonenumber_field', 'dj_language', 'dj_filer', 'ajaxdatatable', 'dj_category', 'corsheaders', 'django_filters', ] INSTALLED_APPS = [ "unfold", "unfold.contrib.filters", "unfold.contrib.import_export", "unfold.contrib.guardian", "unfold.contrib.simple_history", "unfold.contrib.forms", "unfold.contrib.inlines", "whitenoise.runserver_nostatic", # 'limitless_dashboard.apps.DashboardConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', # Added for humanize template tags *THIRD_PARTY_APPS, *LOCAL_APPS, ] AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', # این خط را نگه دارید تا احراز هویت پیش‌فرض کار کند 'apps.account.custom_user_login.CustomLoginBackend', # مسیر به کلاس سفارشی خود ] REDIS_URL = env('REDIS_URL') OTP_SERIVCE_KEY = "33213d78f1234e99b81f94eefda77e45" PHONENUMBER_DEFAULT_REGION = "IR" PHONENUMBER_DB_FORMAT = 'INTERNATIONAL' PHONENUMBER_DEFAULT_FORMAT = 'INTERNATIONAL' AUTH_USER_MODEL = "account.User" MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', "whitenoise.middleware.WhiteNoiseMiddleware", 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', # "django.contrib.auth.middleware.LoginRequiredMiddleware", 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'config.language_code_middleware.language_middleware', 'config.test_auth_middleware.test_auth_middleware', ] ROOT_URLCONF = 'config.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', 'django.template.context_processors.i18n', "utils.admin.variables", ], }, }, ] WSGI_APPLICATION = 'config.wsgi.application' # django google recaptcha default keys RECAPTCHA_PUBLIC_KEY = env('captcha_public_key') RECAPTCHA_PRIVATE_KEY = env('captcha_private_key') APPS_REORDER = { 'auth': { 'icon': 'icon-shield-check', 'name': 'Authentication' }, 'account': { # 'icon': 'icon-', 'name': 'account' } } # Database # https://docs.djangoproject.com/en/5.0/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': env('POSTGRES_DB'), 'USER': env('POSTGRES_USER'), 'PASSWORD': env('POSTGRES_PASSWORD'), 'HOST': env('POSTGRES_HOST'), 'PORT': env('POSTGRES_PORT'), 'ATOMIC_REQUESTS': True, }, } CORS_ALLOW_ALL_ORIGINS = True THUMBNAIL_ALIASES = { '': { 'icon': {'size': (50, 50), 'crop': True}, 'large': {'size': (1200, 620), 'crop': False}, 'medium': {'size': (545, 545), 'crop': False}, 'small': {'size': (150, 150), 'crop': False}, }, } LANGUAGES = [ ('en', _('English')), ('fa', _('Persian')), ('ru', _('Russia')), ] LOCALE_PATHS = [ os.path.join(BASE_DIR, 'locale'), ] CELERY_BROKER_URL = env("REDIS_URL") CELERY_RESULT_BACKEND = env("REDIS_URL") CELERY_ACCEPT_CONTENT = ['application/json'] CELERY_TIMEZONE = 'Asia/Tehran' CELERY_BROKER_TRANSPORT = 'redis' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True # Password validation # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'OPTIONS': { 'min_length': 6, } }, ] REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 16, # 'DEFAULT_AUTHENTICATION_CLASSES': [ # 'apps.account.auth_back.TokenAuthentication2', # ], 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', # 'rest_framework.authentication.SessionAuthentication', ], 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', 'EXCEPTION_HANDLER': 'utils.exceptions.exception_handler', } # Internationalization # https://docs.djangoproject.com/en/5.0/topics/i18n/ LANGUAGE_CODE = 'en' TIME_ZONE = 'Asia/Tehran' USE_I18N = True USE_L10N = True USE_TZ = False STATIC_URL = '/static/' MEDIA_URL = '/media/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] STATIC_ROOT = os.path.join(BASE_DIR, 'static', 'static') MEDIA_ROOT = os.path.join(BASE_DIR, 'static', 'media') # FILER_ADMIN_ICON_SIZES = ('32', '48') FILER_ENABLE_LOGGING = True FILER_DEBUG = True ADMIN_TITLE = 'Imam Javad App' ADMIN_INDEX_TITLE = 'Imam Javad Administration' # Dictionary with phone number ranges and corresponding countries # If a country is in this dictionary, it indicates that the project's OTP service supports that country SERVICE_OTP_COUNTRU_API_KEY = { "Iran": "https://console.melipayamak.com/api/send/simple/33213d78f1234e99b81f94eefda77e45" } SERVICE_OTP_COUNTRY_PHONE_RANGE = { "98": "Iran", "+98": "Iran" } # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_SHOW_CITY_GUIDE_CITY = 'mashhad' FILE_UPLOAD_HANDLERS = [ 'django.core.files.uploadhandler.TemporaryFileUploadHandler', ] EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' EMAIL_PORT = 587 EMAIL_USE_TLS = True EMAIL_HOST_USER = 'aliabdolahi.171@gmail.com' EMAIL_HOST_PASSWORD = 'rkxb nnhx iave fxxt' ###################################################################### # Sessions ###################################################################### SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" LOGIN_URL = "admin:login" LOGIN_REDIRECT_URL = reverse_lazy("admin:index") # STORAGES = { # "default": { # "BACKEND": "django.core.files.storage.FileSystemStorage", # }, # "staticfiles": { # "BACKEND": "whitenoise.storage.CompressedStaticFilesStorage", # }, # } ###################################################################### # Unfold ###################################################################### UNFOLD = { "SITE_TITLE": _("Imam Jawad Admin"), "SITE_HEADER": _("Imam Jawad Admin"), "SITE_SUBHEADER": _("Imam Jawad Online School"), "SITE_DROPDOWN": [ { "icon": "diamond", "title": _("Imam Javad Site"), "link": "https://habibapp.com", }, ], "SITE_SYMBOL": "settings", "SHOW_HISTORY": True, "SHOW_LANGUAGES": True, "ENVIRONMENT": "utils.environment_callback", "DASHBOARD_CALLBACK": "utils.admin.dashboard_callback", "SITE_ICON": { "light": lambda request: static("images/logo1.svg"), # light mode "dark": lambda request: static("images/logo1.svg"), # dark mode }, "SITE_SYMBOL": "speed", "SHOW_BACK_BUTTON": True, # show/hide "Back" button on changeform in header, default: False "THEME": "dark", "LOGIN": { "image": lambda request: static("images/image1.jpg"), }, "COLORS": { "base": { "50": "249 250 251", "100": "243 244 246", "200": "229 231 235", "300": "209 213 219", "400": "156 163 175", "500": "107 114 128", "600": "75 85 99", "700": "55 65 81", "800": "31 41 55", "900": "17 24 39", "950": "3 7 18", }, "primary": { "50": "234 253 243", "100": "208 251 232", "200": "167 247 216", "300": "110 240 189", "400": "37 213 152", "500": "37 208 118", # #25D076 - رنگ دکمه اصلی "600": "29 166 94", "700": "25 136 80", "800": "22 108 66", "900": "20 89 57", "950": "10 53 34", }, "secondary": { "50": "240 253 250", "100": "204 251 241", "200": "153 246 228", "300": "94 234 212", "400": "45 212 191", "500": "1 53 59", # #01353B - رنگ پس‌زمینه "600": "1 43 48", "700": "1 36 40", "800": "1 30 34", "900": "0 26 29", "950": "0 13 15", }, "font": { "subtle-light": "var(--color-base-500)", "subtle-dark": "var(--color-base-400)", "default-light": "var(--color-secondary-500)", # استفاده از رنگ ثانویه برای متن "default-dark": "var(--color-base-300)", "important-light": "var(--color-base-900)", "important-dark": "255 255 255", # #FFFFFF - برای متن سفید در دکمه‌ها }, }, "STYLES": [ # lambda request: static("css/styles.css"), ], "SCRIPTS": [ # lambda request: static("js/chart.min.js"), ], "TABS": [ { "page": "video", "models": ["video.videocollection", "video.pinnedvideocollection", 'video.middlevideocollection',], "items": [ { "title": _("Collections"), "icon": "collections_bookmark", "link": reverse_lazy("admin:video_pinnedvideocollection_changelist"), "active": lambda request: "video/pinnedvideocollection" in request.path and "library/middlevideocollection" not in request.path, }, { "title": _("Middle Collections"), "icon": "view_module", "link": reverse_lazy("admin:video_middlevideocollection_changelist"), "active": lambda request: "video/middlevideocollection" in request.path, }, ], }, { "page": "library", "models": ["library.bookcollection", "library.pinnedbookcollection", 'library.middlebookcollection'], "items": [ { "title": _("Collections"), "icon": "collections_bookmark", "link": reverse_lazy("admin:library_pinnedbookcollection_changelist"), "active": lambda request: "library/pinnedbookcollection" in request.path and "library/middlebookcollection" not in request.path, }, { "title": _("Middle Collections"), "icon": "view_module", "link": reverse_lazy("admin:library_middlebookcollection_changelist"), "active": lambda request: "library/middlebookcollection" in request.path, }, ], }, { "page": "accounts", "models": ["account.user", 'auth.group'], "items": [ { "title": _("Users"), "icon": "sports_motorsports", "link": reverse_lazy("admin:account_user_changelist"), "active": lambda request: request.path == reverse_lazy("admin:account_user_changelist") and "email__isnull" not in request.GET, }, { "title": _("Guest Users"), "icon": "sports_motorsports", "link": lambda request: f"{reverse_lazy('admin:account_user_changelist')}?email__isnull=true", }, ], }, { "page": "authentication", "models": ["auth.group", "auth.permission"], "permission": lambda request: request.user.is_staff, "items": [ { "title": _("Groups"), "icon": "shield", "link": reverse_lazy("admin:auth_group_changelist"), }, ], }, { "page": "courses", "models": [ "course.course", "course.courselesson", "course.courseglossary", "course.courseattachment", "quiz.quiz", ], "items": [ { "title": _("Courses"), "icon": "school", "link": reverse_lazy("admin:course_course_changelist"), "active": lambda request: request.path.startswith(str(reverse_lazy("admin:course_course_changelist"))), }, { "title": _("Course Lessons"), "icon": "menu_book", "link": reverse_lazy("admin:course_courselesson_changelist"), "active": lambda request: request.path.startswith(str(reverse_lazy("admin:course_courselesson_changelist"))), }, { "title": _("Course Attachments"), "icon": "attach_file", "link": reverse_lazy("admin:course_courseattachment_changelist"), "active": lambda request: request.path.startswith(str(reverse_lazy("admin:course_courseattachment_changelist"))), }, { "title": _("Course Glossary"), "icon": "book", "link": reverse_lazy("admin:course_courseglossary_changelist"), "active": lambda request: request.path.startswith(str(reverse_lazy("admin:course_courseglossary_changelist"))), }, { "title": _("Quizzes"), "icon": "quiz", "link": reverse_lazy("admin:quiz_quiz_changelist"), "active": lambda request: request.path.startswith(str(reverse_lazy("admin:quiz_quiz_changelist"))), }, ], }, ], "SIDEBAR": { "show_search": True, "show_all_applications": True, "navigation": [ { "title": _(""), "separator": True, "collapsible": True, "items": [ { "title": _("Dashboard"), "icon": "dashboard", "link": reverse_lazy("admin:index"), }, ], }, { "title": _(""), "items": [ { "title": _("Authentication"), "icon": "shield", "link": reverse_lazy("admin:auth_group_changelist"), "permission": lambda request: request.user.is_staff, }, ], }, { "title": _(""), "items": [ { "title": _("Users"), "icon": "person", "link": reverse_lazy("admin:account_user_changelist"), "permission": lambda request: request.user.is_staff, }, ], }, { "title": _(""), "items": [ { "title": _("Students"), "icon": "school", "link": reverse_lazy("admin:account_studentuser_changelist"), "permission": lambda request: request.user.is_staff, }, ] }, { "title": _(""), "items": [ { "title": _("Professors"), "icon": "person_book", "link": reverse_lazy("admin:account_professoruser_changelist"), "permission": lambda request: request.user.is_staff, }, ] }, { "title": _(""), "items": [ { "title": _("Calender"), "icon": "calendar_today", "link": reverse_lazy("admin:dobodbi_calendar_calendaroccasions_changelist"), "permission": lambda request: request.user.is_staff, }, ], }, { "title": _("Courses"), "collapsible": True, "separator": True, "items": [ { "title": _("Categories"), "icon": "category", "link": reverse_lazy("admin:course_coursecategory_changelist"), }, { "title": _("Courses"), "icon": "school", "link": reverse_lazy("admin:course_course_changelist"), }, { "title": _("Lessons"), "icon": "menu_book", "link": reverse_lazy("admin:course_lesson_changelist"), }, { "title": _("Attachments"), "icon": "attach_file", "link": reverse_lazy("admin:course_attachment_changelist"), }, { "title": _("Glossary"), "icon": "book", "link": reverse_lazy("admin:course_glossary_changelist"), }, { "title": _("Certificates"), "icon": "workspace_premium", "link": reverse_lazy("admin:certificate_certificate_changelist"), }, ] }, { "title": _("Transactions"), "collapsible": True, "separator": True, "items": [ { "title": _("Transactions"), "icon": "payments", "link": reverse_lazy("admin:transaction_transactionparticipant_changelist"), }, ] }, { "title": _("Libraries"), "collapsible": True, "separator": True, "items": [ { "title": _("Books"), "icon": "menu_book", "link": reverse_lazy("admin:library_book_changelist"), }, { "title": _("Categories"), "icon": "category", "link": reverse_lazy("admin:library_category_changelist"), }, { "title": _("Collections"), "icon": "view_module", "link": reverse_lazy("admin:library_pinnedbookcollection_changelist"), }, ] }, { "title": _("Videos"), "collapsible": True, "separator": True, "items": [ { "title": _("Videos"), "icon": "live_tv", "link": reverse_lazy("admin:video_video_changelist"), }, { "title": _("Categories"), "icon": "category", "link": reverse_lazy("admin:video_videocategory_changelist"), }, { "title": _("Collections"), "icon": "view_module", "link": reverse_lazy("admin:video_pinnedvideocollection_changelist"), }, { "title": _("Playlists"), "icon": "playlist_play", "link": reverse_lazy("admin:video_videoplaylist_changelist"), # "active": lambda request: "video/videoplaylist" in request.path, }, ] }, { "title": _("Articles"), "collapsible": True, "separator": True, "items": [ { "title": _("Articles"), "icon": "article", "link": reverse_lazy("admin:article_article_changelist"), }, { "title": _("Categories"), "icon": "category", "link": reverse_lazy("admin:article_articlecategory_changelist"), }, { "title": _("Collections"), "icon": "view_module", "link": reverse_lazy("admin:article_pinnedarticlecollection_changelist"), }, { "title": _("Article Contents"), "icon": "text_snippet", "link": reverse_lazy("admin:article_articlecontent_changelist"), }, ] }, { "title": _("Podcasts"), "collapsible": True, "separator": True, "items": [ { "title": _("Podcasts"), "icon": "headset", "link": reverse_lazy("admin:podcast_podcast_changelist"), }, { "title": _("Categories"), "icon": "category", "link": reverse_lazy("admin:podcast_podcastcategory_changelist"), }, { "title": _("Collections"), "icon": "view_module", "link": reverse_lazy("admin:podcast_pinnedpodcastcollection_changelist"), }, { "title": _("Playlists"), "icon": "playlist_play", "link": reverse_lazy("admin:podcast_podcastplaylist_changelist"), }, { "title": _("User Playlists"), "icon": "person_add", "link": reverse_lazy("admin:podcast_userplaylist_changelist"), }, ] }, { "title": _(""), "collapsible": True, "separator": True, "items": [ { "title": _("Chat Rooms"), "icon": "forum", "link": reverse_lazy("admin:chat_roommessage_changelist"), }, # { # "title": _("Chat Messages"), # "icon": "chat", # "link": reverse_lazy("admin:apps_chat_chatmessage_changelist"), # }, # { # "title": _("Read Status"), # "icon": "mark_chat_read", # "link": reverse_lazy("admin:apps_chat_messagereadstatus_changelist"), # }, ] }, { "title": "", "items": [ { "title": _("Global Preferences"), "icon": "settings", "link": reverse_lazy("admin:dynamic_preferences_globalpreferencemodel_changelist"), }, # You can add more preference sections here ], }, # "STYLES": [ # lambda request: static("css/styles.css"), # ], # "SCRIPTS": [ # lambda request: static("js/scripts.js"), # ], # { # "title": _("Hadis"), # "collapsible": True, # "separator": True, # "items": [ # { # "title": _("Hadis Categories"), # "icon": "category", # "link": reverse_lazy("admin:hadis_hadiscategory_changelist"), # }, # # { # # "title": _("Hadis"), # # "icon": "format_quote", # # "link": reverse_lazy("admin:hadis_hadis_changelist"), # # }, # ] # }, ], }, } UNFOLD_STUDIO_DEFAULT_FRAGMENT = "color-schemes" UNFOLD_STUDIO_PERMISSION = lambda request: request.user.is_authenticated PLAUSIBLE_DOMAIN = env("PLAUSIBLE_DOMAIN")