From 369fa41c3f8a5791a429368828fca10b2aeaa0a8 Mon Sep 17 00:00:00 2001 From: Kryslogem <118667583+Kryslogem@users.noreply.github.com> Date: Sat, 7 Feb 2026 22:27:12 +0700 Subject: [PATCH 1/7] Add database configuration for Neon PostgresSQL --- .env.example | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 9cccd1ee..3039e3e9 100644 --- a/.env.example +++ b/.env.example @@ -12,8 +12,17 @@ EMAIL_FROM_ADDRESS="SkyLearn " EMAIL_HOST_USER="" EMAIL_HOST_PASSWORD="" +# ============================= +# Database Neon - PostgresSQL +DB_ENGINE=django.db.backends.postgresql +DB_NAME=neondb +DB_USER=neondb_owner +DB_PASSWORD=npg_B0Hujnsh8zEv +DB_HOST=ep-gentle-shape-a1unb4h2-pooler.ap-southeast-1.aws.neon.tech +DB_PORT=5432 + # ============================= # Other DEBUG=True -SECRET_KEY="" \ No newline at end of file +SECRET_KEY="" From b5ed671103d14ffbf1ca361a18217c40aec5476e Mon Sep 17 00:00:00 2001 From: Kryslogem <118667583+Kryslogem@users.noreply.github.com> Date: Sat, 14 Feb 2026 14:59:43 +0700 Subject: [PATCH 2/7] Switch database from SQLite to PostgreSQL Replaced SQLite database configuration with PostgreSQL using dj_database_url. --- config/settings.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/config/settings.py b/config/settings.py index 43f70b16..970a2d35 100644 --- a/config/settings.py +++ b/config/settings.py @@ -107,11 +107,14 @@ # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases +import dj_database_url + DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), - } + 'default': dj_database_url.config( + default=f"postgres://{config('DB_USER')}:{config('DB_PASSWORD')}@{config('DB_HOST')}:{config('DB_PORT')}/{config('DB_NAME')}", + conn_max_age=600, + ssl_require=True + ) } # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-DEFAULT_AUTO_FIELD From 560c6320aea25f39e7c1f432b954ae2eea9b35ca Mon Sep 17 00:00:00 2001 From: Kryslogem <118667583+Kryslogem@users.noreply.github.com> Date: Sat, 14 Feb 2026 15:00:07 +0700 Subject: [PATCH 3/7] Modify email backend settings in .env.example Updated email backend configuration for development and production environments. --- .env.example | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 3039e3e9..7d713499 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,18 @@ # ============================= # Email config -# For development or quick testing use console as the email backend +# This line is the "magic" fix. It tells Django to print emails to the terminal +# instead of trying to send them through a real server. EMAIL_BACKEND="django.core.mail.backends.console.EmailBackend" -# For production use smtp, uncomment the below variable -# EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend" + EMAIL_HOST="smtp.gmail.com" EMAIL_PORT=587 EMAIL_USE_TLS=True EMAIL_FROM_ADDRESS="SkyLearn " -EMAIL_HOST_USER="" -EMAIL_HOST_PASSWORD="" + +# These two must exist for your config('NAME') calls to work +EMAIL_HOST_USER="youremail@example.com" +EMAIL_HOST_PASSWORD="yourpassword" # ============================= # Database Neon - PostgresSQL @@ -23,6 +25,5 @@ DB_PORT=5432 # ============================= # Other - DEBUG=True -SECRET_KEY="" +SECRET_KEY="any-random-string-here" From c2fad1cb4b3d36a4d5aea4327ef9e4d9db429ba8 Mon Sep 17 00:00:00 2001 From: Kryslogem <118667583+Kryslogem@users.noreply.github.com> Date: Sat, 14 Feb 2026 18:43:57 +0700 Subject: [PATCH 4/7] Add Cloudinary as cloud storage --- .env.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.example b/.env.example index 7d713499..242c62a6 100644 --- a/.env.example +++ b/.env.example @@ -23,6 +23,10 @@ DB_PASSWORD=npg_B0Hujnsh8zEv DB_HOST=ep-gentle-shape-a1unb4h2-pooler.ap-southeast-1.aws.neon.tech DB_PORT=5432 +# ============================= +# Cloudinary Storage - Cloudinary +CLOUDINARY_URL=cloudinary://781526684325383:F1IcPCOHWkItagYigXGm-3j6VHc@ddr6xe1vn + # ============================= # Other DEBUG=True From 22e9924cb32c536e5d153fa8bf3d5926480777fc Mon Sep 17 00:00:00 2001 From: Kryslogem <118667583+Kryslogem@users.noreply.github.com> Date: Sat, 14 Feb 2026 18:44:53 +0700 Subject: [PATCH 5/7] Integrate Cloudinary for media file storage Added Cloudinary configuration for media file storage. --- config/settings.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/config/settings.py b/config/settings.py index 970a2d35..3284bdc5 100644 --- a/config/settings.py +++ b/config/settings.py @@ -52,6 +52,8 @@ "crispy_forms", "crispy_bootstrap5", "django_filters", + "cloudinary_storage", + "cloudinary", ] # Custom apps @@ -272,3 +274,16 @@ def gettext(s): (SECOND, _("Second")), (THIRD, _("Third")), ) + +import cloudinary + +# Read Cloudinary credentials from .env +CLOUDINARY_STORAGE = { + 'CLOUDINARY_URL': config('CLOUDINARY_URL') +} + +# Tell Django to upload all media files to Cloudinary +DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.RawMediaCloudinaryStorage' + +# Keep your static files (CSS/JS) local for now +STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' From 45f39592f8774da93c41f612a569fabcd7bbb851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A1i=20Ho=C3=A0ng=20Gia=20Tho=E1=BA=A1i?= Date: Sat, 7 Mar 2026 23:18:51 +0700 Subject: [PATCH 6/7] Cloudinary_connect --- accounts/views.py | 4 ++-- config/settings.py | 10 ++++------ requirements/base.txt | 7 ++++++- templates/navbar.html | 4 ++++ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/accounts/views.py b/accounts/views.py index 910df567..f44b3a8f 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -96,7 +96,7 @@ def profile(request): student = get_object_or_404(Student, student__pk=request.user.id) parent = Parent.objects.filter(student=student).first() courses = TakenCourse.objects.filter( - student__student__id=request.user.id, course__level=student.level + student__student__id=request.user.id ) context.update( { @@ -146,7 +146,7 @@ def profile_single(request, user_id): elif user.is_student: student = get_object_or_404(Student, student__pk=user_id) courses = TakenCourse.objects.filter( - student__student__id=user_id, course__level=student.level + student__student__id=user_id ) context.update( { diff --git a/config/settings.py b/config/settings.py index 3284bdc5..8acf2097 100644 --- a/config/settings.py +++ b/config/settings.py @@ -13,6 +13,7 @@ import os from decouple import config from django.utils.translation import gettext_lazy as _ +import cloudinary # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -275,15 +276,12 @@ def gettext(s): (THIRD, _("Third")), ) -import cloudinary - # Read Cloudinary credentials from .env CLOUDINARY_STORAGE = { - 'CLOUDINARY_URL': config('CLOUDINARY_URL') + 'CLOUD_NAME': config('CLOUDINARY_CLOUD_NAME'), + 'API_KEY': config('CLOUDINARY_API_KEY'), + 'API_SECRET': config('CLOUDINARY_API_SECRET'), } # Tell Django to upload all media files to Cloudinary DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.RawMediaCloudinaryStorage' - -# Keep your static files (CSS/JS) local for now -STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' diff --git a/requirements/base.txt b/requirements/base.txt index 0ff367a5..fd20701f 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -11,6 +11,7 @@ crispy-bootstrap5==0.7 # https://github.com/django-crispy-forms/crispy-bootstra django-filter==23.5 # https://github.com/carltongibson/django-filter django-modeltranslation==0.18.11 # https://github.com/Buren/django-modeltranslation + # PDF generator reportlab==4.0.4 xhtml2pdf==0.2.15 @@ -27,4 +28,8 @@ gopay==2.0.1 # AI core langchain -langchain-google-genai \ No newline at end of file +langchain-google-genai + +#Cloudinary +psycopg2-binary dj-database-url +cloudinary django-cloudinary-storage \ No newline at end of file diff --git a/templates/navbar.html b/templates/navbar.html index dece5ec0..6853536a 100644 --- a/templates/navbar.html +++ b/templates/navbar.html @@ -17,12 +17,16 @@