diff --git a/cart/__pycache__/cart.cpython-311.pyc b/cart/__pycache__/cart.cpython-311.pyc index d00aa7e..7b46ed5 100644 Binary files a/cart/__pycache__/cart.cpython-311.pyc and b/cart/__pycache__/cart.cpython-311.pyc differ diff --git a/cart/cart.py b/cart/cart.py index 4191d0a..44a89ec 100644 --- a/cart/cart.py +++ b/cart/cart.py @@ -9,19 +9,24 @@ class Cart: Initialize the cart. """ self.session = request.session - cart = self.session.get(settings.CART_SESSION_ID) + user_id = self.session.get('keycloak_user_id') # Используйте идентификатор пользователя из сессии + if user_id: + cart_session_id = f"{settings.CART_SESSION_ID}_{user_id}" # Создайте уникальный ключ сессии для корзины + else: + cart_session_id = settings.CART_SESSION_ID + cart = self.session.get(cart_session_id) if not cart: # save an empty cart in the session - cart = self.session[settings.CART_SESSION_ID] = {} + cart = self.session[cart_session_id] = {} self.cart = cart + self.cart_session_id = cart_session_id def __iter__(self): """ Iterate over the items in the cart and get the products from the database. """ - product_ids = self.cart.keys() - # get the product objects and add them to the cart + product_ids = self.cart.keys() # get the product objects and add them to the cart products = Product.objects.filter(id__in=product_ids) cart = self.cart.copy() for product in products: @@ -55,6 +60,8 @@ class Cart: # mark the session as "modified" to make sure it gets saved self.session.modified = True + self.session[self.cart_session_id] = self.cart + def remove(self, product): """ Remove a product from the cart. diff --git a/db.sqlite3 b/db.sqlite3 index e416f0b..a2d52fd 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/django.log b/django.log new file mode 100644 index 0000000..d760ddc --- /dev/null +++ b/django.log @@ -0,0 +1,15 @@ +INFO 2024-02-23 13:45:46,251 autoreload Watching for file changes with StatReloader +INFO 2024-02-23 13:46:13,396 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:46:43,771 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:46:48,385 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:46:48,633 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:46:48,830 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:48:22,691 autoreload Watching for file changes with StatReloader +INFO 2024-02-23 13:48:32,058 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:48:37,176 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:48:37,585 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:48:44,312 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 13:48:51,761 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 21:15:16,575 autoreload Watching for file changes with StatReloader +INFO 2024-02-23 21:15:27,243 views Redirecting to Keycloak for authentication. +INFO 2024-02-23 21:15:32,818 views Redirecting to Keycloak for authentication. diff --git a/djangoProject1/__pycache__/settings.cpython-311.pyc b/djangoProject1/__pycache__/settings.cpython-311.pyc index 598ee6c..c05326b 100644 Binary files a/djangoProject1/__pycache__/settings.cpython-311.pyc and b/djangoProject1/__pycache__/settings.cpython-311.pyc differ diff --git a/djangoProject1/__pycache__/urls.cpython-311.pyc b/djangoProject1/__pycache__/urls.cpython-311.pyc index 081884f..21a4f6b 100644 Binary files a/djangoProject1/__pycache__/urls.cpython-311.pyc and b/djangoProject1/__pycache__/urls.cpython-311.pyc differ diff --git a/djangoProject1/settings.py b/djangoProject1/settings.py index 300d0f8..0275965 100644 --- a/djangoProject1/settings.py +++ b/djangoProject1/settings.py @@ -25,7 +25,7 @@ SECRET_KEY = 'django-insecure-)p-ed99i+^)@_t33f65!y8eqn23!&kt)zc(ht$8h7e8#1k(o$f # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['127.0.0.1'] # Пример для разработки и продакшена CART_SESSION_ID = 'cart' # Application definition @@ -33,6 +33,7 @@ CART_SESSION_ID = 'cart' INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', + 'django_extensions', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', @@ -40,6 +41,9 @@ INSTALLED_APPS = [ 'main.apps.MainConfig', 'cart.apps.CartConfig', 'orders.apps.OrdersConfig', + 'users.apps.UsersConfig', + + ] MIDDLEWARE = [ @@ -143,3 +147,42 @@ EMAIL_HOST_USER = 'fhjj3590@gmail.com' EMAIL_HOST_PASSWORD = 'uzmd nmit yxwc sgox' # Предполагается, что это сгенерированный пароль для приложений EMAIL_PORT = 587 EMAIL_USE_TLS = True + + +KEYCLOAK_CONFIG = { + 'SERVER_URL': 'https://auth.myterior.kz', + 'REALM': 'Harmony', + 'CLIENT_ID': 'lowlight', + 'CLIENT_SECRET': 'u31Kvkj9V2npxdwJUODReO3YJ2w2iMul', + 'CALLBACK_URL': 'http://127.0.0.1:8000/products/', +} + + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '{levelname} {asctime} {module} {message}', + 'style': '{', + }, + }, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + 'file': { + 'level': 'INFO', + 'class': 'logging.FileHandler', + 'filename': 'django.log', + 'formatter': 'verbose', + }, + }, + 'loggers': { + '': { # 'root' logger + 'handlers': ['console', 'file'], + 'level': 'INFO', + }, + }, +} diff --git a/djangoProject1/urls.py b/djangoProject1/urls.py index 21b3939..7ab1a29 100644 --- a/djangoProject1/urls.py +++ b/djangoProject1/urls.py @@ -1,32 +1,15 @@ -""" -URL configuration for Harmony project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/5.0/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" from django.contrib import admin -from django.urls import path,include +from django.urls import path, include from django.conf import settings from django.conf.urls.static import static + urlpatterns = [ path('admin/', admin.site.urls), -path('cart/', include('cart.urls', namespace='cart')), + path('cart/', include('cart.urls', namespace='cart')), path('orders/', include('orders.urls', namespace='orders')), - path('', include('main.urls', namespace='main')), - - + path('auth/', include('users.urls')), # Подключение URL приложения users ] + if settings.DEBUG: - urlpatterns += static(settings.MEDIA_URL, - document_root=settings.MEDIA_ROOT) \ No newline at end of file + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/invoice_image.png b/invoice_image.png index 1ed3edc..26edb7c 100644 Binary files a/invoice_image.png and b/invoice_image.png differ diff --git a/main/__pycache__/models.cpython-311.pyc b/main/__pycache__/models.cpython-311.pyc index 765a004..4811dd8 100644 Binary files a/main/__pycache__/models.cpython-311.pyc and b/main/__pycache__/models.cpython-311.pyc differ diff --git a/main/__pycache__/urls.cpython-311.pyc b/main/__pycache__/urls.cpython-311.pyc index 0b76805..e66477b 100644 Binary files a/main/__pycache__/urls.cpython-311.pyc and b/main/__pycache__/urls.cpython-311.pyc differ diff --git a/main/migrations/0002_alter_product_price.py b/main/migrations/0002_alter_product_price.py new file mode 100644 index 0000000..1a6fac7 --- /dev/null +++ b/main/migrations/0002_alter_product_price.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-22 09:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='product', + name='price', + field=models.IntegerField(max_length=19), + ), + ] diff --git a/main/migrations/__pycache__/0002_alter_product_price.cpython-311.pyc b/main/migrations/__pycache__/0002_alter_product_price.cpython-311.pyc new file mode 100644 index 0000000..1416ec9 Binary files /dev/null and b/main/migrations/__pycache__/0002_alter_product_price.cpython-311.pyc differ diff --git a/main/models.py b/main/models.py index 45efad0..8ab9847 100644 --- a/main/models.py +++ b/main/models.py @@ -27,8 +27,7 @@ class Product(models.Model): image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True) description = models.TextField(blank=True) - price = models.DecimalField(max_digits=10, - decimal_places=2) + price = models.IntegerField(max_length=19) available = models.BooleanField(default=True) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) diff --git a/main/static/deps/icons/facebook.svg b/main/static/deps/icons/facebook.svg new file mode 100644 index 0000000..29a2e95 --- /dev/null +++ b/main/static/deps/icons/facebook.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/main/static/deps/icons/google.svg b/main/static/deps/icons/google.svg new file mode 100644 index 0000000..0ea9378 --- /dev/null +++ b/main/static/deps/icons/google.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/main/templates/main/base.html b/main/templates/main/base.html index 93535e8..eac5a84 100644 --- a/main/templates/main/base.html +++ b/main/templates/main/base.html @@ -48,22 +48,28 @@ -{# #} + +
  • Личный кабинет
  • + +{% if request.session.keycloak_user_id %} + +{% endif %} + + + + diff --git a/main/templates/main/product/profile.html b/main/templates/main/product/profile.html new file mode 100644 index 0000000..c364b8c --- /dev/null +++ b/main/templates/main/product/profile.html @@ -0,0 +1,7 @@ +{% extends "main/base.html" %} + +{% block content %} +

    Личный кабинет

    +

    Привет, {{ username }}!

    + +{% endblock %} diff --git a/media/products/2024/02/22/i.webp b/media/products/2024/02/22/i.webp new file mode 100644 index 0000000..bf99c16 Binary files /dev/null and b/media/products/2024/02/22/i.webp differ diff --git a/orders/__pycache__/models.cpython-311.pyc b/orders/__pycache__/models.cpython-311.pyc index 1e7ba8c..e46265e 100644 Binary files a/orders/__pycache__/models.cpython-311.pyc and b/orders/__pycache__/models.cpython-311.pyc differ diff --git a/orders/__pycache__/views.cpython-311.pyc b/orders/__pycache__/views.cpython-311.pyc index 702bf93..3753683 100644 Binary files a/orders/__pycache__/views.cpython-311.pyc and b/orders/__pycache__/views.cpython-311.pyc differ diff --git a/orders/migrations/0002_alter_orderitem_price.py b/orders/migrations/0002_alter_orderitem_price.py new file mode 100644 index 0000000..08b9ddf --- /dev/null +++ b/orders/migrations/0002_alter_orderitem_price.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.2 on 2024-02-22 09:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('orders', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='orderitem', + name='price', + field=models.IntegerField(max_length=19), + ), + ] diff --git a/orders/migrations/__pycache__/0002_alter_orderitem_price.cpython-311.pyc b/orders/migrations/__pycache__/0002_alter_orderitem_price.cpython-311.pyc new file mode 100644 index 0000000..ff22b3f Binary files /dev/null and b/orders/migrations/__pycache__/0002_alter_orderitem_price.cpython-311.pyc differ diff --git a/orders/models.py b/orders/models.py index 4a2f98f..bf7151e 100644 --- a/orders/models.py +++ b/orders/models.py @@ -29,7 +29,7 @@ class Order(models.Model): class OrderItem(models.Model): order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE) product = models.ForeignKey(Product, related_name='order_items', on_delete=models.CASCADE) - price = models.DecimalField(max_digits=10, decimal_places=2) + price = models.IntegerField(max_length=19) quantity = models.PositiveIntegerField(default=1) def __str__(self): diff --git a/orders/views.py b/orders/views.py index 5854289..ead5941 100644 --- a/orders/views.py +++ b/orders/views.py @@ -3,6 +3,7 @@ from .models import OrderItem, Order from .forms import OrderCreateForm from cart.cart import Cart from django.conf import settings +from decimal import Decimal from .utils import send_invoice_via_email @@ -27,4 +28,8 @@ def order_create(request): def order_created(request, order_id): order = get_object_or_404(Order, id=order_id) - return render(request, 'orders/order/created.html', {'order': order}) \ No newline at end of file + return render(request, 'orders/order/created.html', {'order': order}) + + + + diff --git a/users/__init__.py b/users/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/__pycache__/__init__.cpython-311.pyc b/users/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2701d7e Binary files /dev/null and b/users/__pycache__/__init__.cpython-311.pyc differ diff --git a/users/__pycache__/admin.cpython-311.pyc b/users/__pycache__/admin.cpython-311.pyc new file mode 100644 index 0000000..4ab2eb4 Binary files /dev/null and b/users/__pycache__/admin.cpython-311.pyc differ diff --git a/users/__pycache__/apps.cpython-311.pyc b/users/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000..5b9f2bc Binary files /dev/null and b/users/__pycache__/apps.cpython-311.pyc differ diff --git a/users/__pycache__/models.cpython-311.pyc b/users/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..83bccb1 Binary files /dev/null and b/users/__pycache__/models.cpython-311.pyc differ diff --git a/users/__pycache__/urls.cpython-311.pyc b/users/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..e6a7c7b Binary files /dev/null and b/users/__pycache__/urls.cpython-311.pyc differ diff --git a/users/__pycache__/views.cpython-311.pyc b/users/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..caca517 Binary files /dev/null and b/users/__pycache__/views.cpython-311.pyc differ diff --git a/users/admin.py b/users/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/users/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/users/apps.py b/users/apps.py new file mode 100644 index 0000000..72b1401 --- /dev/null +++ b/users/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'users' diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/migrations/__pycache__/__init__.cpython-311.pyc b/users/migrations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..3d34eb2 Binary files /dev/null and b/users/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/users/models.py b/users/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/users/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/users/tests.py b/users/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/users/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/users/urls.py b/users/urls.py new file mode 100644 index 0000000..d9eb864 --- /dev/null +++ b/users/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from .views import keycloak_login, keycloak_callback, keycloak_logout +from .views import profile +urlpatterns = [ + path('login/', keycloak_login, name='keycloak_login'), + path('callback/', keycloak_callback, name='keycloak_callback'), + path('logout/', keycloak_logout, name='keycloak_logout'), +path('profile/', profile, name='profile'), + +] diff --git a/users/views.py b/users/views.py new file mode 100644 index 0000000..e88442c --- /dev/null +++ b/users/views.py @@ -0,0 +1,89 @@ +from django.shortcuts import redirect,render +from django.http import HttpResponse +from keycloak import KeycloakOpenID, KeycloakGetError +from django.conf import settings +import logging + +# Настройка логгера для текущего модуля +logger = logging.getLogger(__name__) + +# Функция для начала процесса аутентификации с Keycloak +def keycloak_login(request): + try: + keycloak_openid = KeycloakOpenID( + server_url=settings.KEYCLOAK_CONFIG['SERVER_URL'], + client_id=settings.KEYCLOAK_CONFIG['CLIENT_ID'], + realm_name=settings.KEYCLOAK_CONFIG['REALM'], + client_secret_key=settings.KEYCLOAK_CONFIG['CLIENT_SECRET'] + ) + auth_url = keycloak_openid.auth_url(redirect_uri=settings.KEYCLOAK_CONFIG['CALLBACK_URL']) + logger.info("Redirecting to Keycloak for authentication.") + return redirect(auth_url) + except Exception as e: + logger.error(f"Error during Keycloak login: {e}") + return HttpResponse("Ошибка при попытке аутентификации через Keycloak.") + +# Функция обратного вызова для обработки ответа от Keycloak +def keycloak_callback(request): + code = request.GET.get('code') + if code: + try: + keycloak_openid = KeycloakOpenID( + server_url=settings.KEYCLOAK_CONFIG['SERVER_URL'], + client_id=settings.KEYCLOAK_CONFIG['CLIENT_ID'], + realm_name=settings.KEYCLOAK_CONFIG['REALM'], + client_secret_key=settings.KEYCLOAK_CONFIG['CLIENT_SECRET'] + ) + + token = keycloak_openid.token( + grant_type=['authorization_code'], + code=code, + redirect_uri=settings.KEYCLOAK_CONFIG['CALLBACK_URL'] + ) + + userinfo = keycloak_openid.userinfo(token['access_token']) + logger.info(f"User authenticated with Keycloak: {userinfo}") + + request.session['keycloak_user_id'] = userinfo['sub'] + request.session['username'] = userinfo.get('preferred_username', 'Guest') + + return redirect('http://127.0.0.1:8000/products/') + except KeycloakGetError as e: + logger.error(f"Keycloak authentication error: {e}") + return HttpResponse("Ошибка аутентификации.") + except Exception as e: + logger.error(f"Unexpected error during Keycloak callback: {e}") + return HttpResponse("Неожиданная ошибка.") + else: + logger.warning("Authentication code not provided.") + return HttpResponse("Код аутентификации не предоставлен.") + +# Функция для выхода из системы +def keycloak_logout(request): + try: + request.session.flush() + logger.info("User logged out.") + return redirect('http://127.0.0.1:8000/') + except Exception as e: + logger.error(f"Error during logout: {e}") + return HttpResponse("Ошибка при выходе из системы.") + + + + + +def profile(request): + # Проверяем, аутентифицирован ли пользователь + if 'keycloak_user_id' in request.session: + # Извлекаем данные пользователя из сессии + user_id = request.session['keycloak_user_id'] + username = request.session.get('username', 'Гость') + logger.info(f"Keycloak user ID: {request.session['keycloak_user_id']}, Username: {request.session['username']},{username}") + + + + # Отображаем шаблон, передавая в него данные пользователя + return render(request, 'main/product/profile.html', {'username': username}) + else: + # Если пользователь не аутентифицирован, перенаправляем на страницу входа + return redirect('keycloak_login')