Fix home button routes and login redirects
All checks were successful
Build and Push Docker Image / build (push) Successful in 41s
All checks were successful
Build and Push Docker Image / build (push) Successful in 41s
This commit is contained in:
2
.env
2
.env
@@ -9,6 +9,8 @@ USE_X_FORWARDED_HOST=true
|
|||||||
SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
|
SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
|
||||||
SECURE_REFERRER_POLICY=strict-origin-when-cross-origin
|
SECURE_REFERRER_POLICY=strict-origin-when-cross-origin
|
||||||
SITE_NAME=SantehRay
|
SITE_NAME=SantehRay
|
||||||
|
HOME_ADVANTAGES_LEFT_CATEGORY_SLUG=santehnika
|
||||||
|
HOME_ADVANTAGES_RIGHT_CATEGORY_SLUG=otoplenie
|
||||||
LOGIN_URL=/users/login/
|
LOGIN_URL=/users/login/
|
||||||
LOGIN_REDIRECT_URL=/users/profile/
|
LOGIN_REDIRECT_URL=/users/profile/
|
||||||
LOGOUT_REDIRECT_URL=/users/login/
|
LOGOUT_REDIRECT_URL=/users/login/
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ USE_X_FORWARDED_HOST=true
|
|||||||
SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
|
SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
|
||||||
SECURE_REFERRER_POLICY=strict-origin-when-cross-origin
|
SECURE_REFERRER_POLICY=strict-origin-when-cross-origin
|
||||||
SITE_NAME=SantehRay
|
SITE_NAME=SantehRay
|
||||||
|
HOME_ADVANTAGES_LEFT_CATEGORY_SLUG=santehnika
|
||||||
|
HOME_ADVANTAGES_RIGHT_CATEGORY_SLUG=otoplenie
|
||||||
LOGIN_URL=/users/login/
|
LOGIN_URL=/users/login/
|
||||||
LOGIN_REDIRECT_URL=/users/profile/
|
LOGIN_REDIRECT_URL=/users/profile/
|
||||||
LOGOUT_REDIRECT_URL=/users/login/
|
LOGOUT_REDIRECT_URL=/users/login/
|
||||||
|
|||||||
@@ -89,6 +89,20 @@ class HomePopularProductsTests(TestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.context["home_products"]), 6)
|
self.assertEqual(len(response.context["home_products"]), 6)
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
HOME_ADVANTAGES_LEFT_CATEGORY_SLUG="custom-left",
|
||||||
|
HOME_ADVANTAGES_RIGHT_CATEGORY_SLUG="custom-right",
|
||||||
|
)
|
||||||
|
def test_home_advantages_buttons_use_configured_category_slugs(self):
|
||||||
|
Category.objects.create(name="Custom left", slug="custom-left")
|
||||||
|
Category.objects.create(name="Custom right", slug="custom-right")
|
||||||
|
|
||||||
|
response = self.client.get(reverse("home"))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertContains(response, 'href="/catalog/custom-left/?new=1"', html=False)
|
||||||
|
self.assertContains(response, 'href="/catalog/custom-right/?sale=1"', html=False)
|
||||||
|
|
||||||
|
|
||||||
class FaviconTests(SimpleTestCase):
|
class FaviconTests(SimpleTestCase):
|
||||||
def test_favicon_route_returns_icon(self):
|
def test_favicon_route_returns_icon(self):
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
@@ -9,7 +10,7 @@ from django.contrib import messages
|
|||||||
|
|
||||||
from favorites.services import get_user_favorite_item_ids
|
from favorites.services import get_user_favorite_item_ids
|
||||||
from home.forms import FaqQuestionForm
|
from home.forms import FaqQuestionForm
|
||||||
from items.models import Item
|
from items.models import Category, Item
|
||||||
from orders.services import get_user_cart_item_ids
|
from orders.services import get_user_cart_item_ids
|
||||||
|
|
||||||
|
|
||||||
@@ -29,6 +30,19 @@ CONTACT_MAP_EXTERNAL_URL = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_home_category_url(category_slug: str, **query_params: str) -> str:
|
||||||
|
normalized_slug = (category_slug or "").strip().lower()
|
||||||
|
base_url = "/catalog/"
|
||||||
|
if normalized_slug and Category.objects.filter(slug=normalized_slug).exists():
|
||||||
|
base_url = f"/catalog/{normalized_slug}/"
|
||||||
|
|
||||||
|
clean_query_params = {key: value for key, value in query_params.items() if value}
|
||||||
|
if not clean_query_params:
|
||||||
|
return base_url
|
||||||
|
|
||||||
|
return f"{base_url}?{urlencode(clean_query_params)}"
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
form = FaqQuestionForm(request.POST or None)
|
form = FaqQuestionForm(request.POST or None)
|
||||||
|
|
||||||
@@ -76,6 +90,14 @@ def index(request):
|
|||||||
return render(request=request, template_name='home/index.html', context={
|
return render(request=request, template_name='home/index.html', context={
|
||||||
"faq_form": form,
|
"faq_form": form,
|
||||||
"home_products": home_products,
|
"home_products": home_products,
|
||||||
|
"home_advantages_left_url": build_home_category_url(
|
||||||
|
settings.HOME_ADVANTAGES_LEFT_CATEGORY_SLUG,
|
||||||
|
new="1",
|
||||||
|
),
|
||||||
|
"home_advantages_right_url": build_home_category_url(
|
||||||
|
settings.HOME_ADVANTAGES_RIGHT_CATEGORY_SLUG,
|
||||||
|
sale="1",
|
||||||
|
),
|
||||||
"favorite_item_ids": get_user_favorite_item_ids(request.user),
|
"favorite_item_ids": get_user_favorite_item_ids(request.user),
|
||||||
"cart_item_ids": get_user_cart_item_ids(request.user),
|
"cart_item_ids": get_user_cart_item_ids(request.user),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -339,6 +339,9 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|||||||
|
|
||||||
SITE_NAME = os.getenv("SITE_NAME", "SantehRay")
|
SITE_NAME = os.getenv("SITE_NAME", "SantehRay")
|
||||||
|
|
||||||
|
HOME_ADVANTAGES_LEFT_CATEGORY_SLUG = os.getenv("HOME_ADVANTAGES_LEFT_CATEGORY_SLUG", "santehnika")
|
||||||
|
HOME_ADVANTAGES_RIGHT_CATEGORY_SLUG = os.getenv("HOME_ADVANTAGES_RIGHT_CATEGORY_SLUG", "otoplenie")
|
||||||
|
|
||||||
LOGIN_URL = os.getenv("LOGIN_URL", "/users/login/")
|
LOGIN_URL = os.getenv("LOGIN_URL", "/users/login/")
|
||||||
LOGIN_REDIRECT_URL = os.getenv("LOGIN_REDIRECT_URL", "/users/profile/")
|
LOGIN_REDIRECT_URL = os.getenv("LOGIN_REDIRECT_URL", "/users/profile/")
|
||||||
LOGOUT_REDIRECT_URL = os.getenv("LOGOUT_REDIRECT_URL", "/users/login/")
|
LOGOUT_REDIRECT_URL = os.getenv("LOGOUT_REDIRECT_URL", "/users/login/")
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="/catalog/">Каталог</a></li>
|
<li><a href="/catalog/">Каталог</a></li>
|
||||||
<li><a href="{% url 'services' %}">Услуги</a></li>
|
<li><a href="{% url 'services' %}">Услуги</a></li>
|
||||||
<li><a href="/catalog/">Акции</a></li>
|
<li><a href="/catalog/?sale=1">Акции</a></li>
|
||||||
<li><a href="/catalog/">Новинки</a></li>
|
<li><a href="/catalog/?new=1">Новинки</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-col">
|
<div class="footer-col">
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
<div class="flex-right">
|
<div class="flex-right">
|
||||||
<h3 class="advantages-card-splash">Новинки в каталоге</h3>
|
<h3 class="advantages-card-splash">Новинки в каталоге</h3>
|
||||||
<h2 class="advantages-card-title text-align-right">Сантехническое оборудование</h2>
|
<h2 class="advantages-card-title text-align-right">Сантехническое оборудование</h2>
|
||||||
<a href="/catalog?category=plumbing" class="advantages-card-button">Смотреть</a>
|
<a href="{{ home_advantages_left_url }}" class="advantages-card-button">Смотреть</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
<div class="advantages-card-content">
|
<div class="advantages-card-content">
|
||||||
<h3 class="advantages-card-splash">Большая распродажа</h3>
|
<h3 class="advantages-card-splash">Большая распродажа</h3>
|
||||||
<h2 class="advantages-card-title">Предметы декора</h2>
|
<h2 class="advantages-card-title">Предметы декора</h2>
|
||||||
<a href="/catalog?category=decoration" class="advantages-card-button">Смотреть</a>
|
<a href="{{ home_advantages_right_url }}" class="advantages-card-button">Смотреть</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="kitchen-content">
|
<div class="kitchen-content">
|
||||||
<p>Успей заказать с большой выгодой и получите доставку в подарок!</p>
|
<p>Успей заказать с большой выгодой и получите доставку в подарок!</p>
|
||||||
<h2>ГОТОВОЕ РЕШЕНИЕ ДЛЯ КУХНИ</h2>
|
<h2>ГОТОВОЕ РЕШЕНИЕ ДЛЯ КУХНИ</h2>
|
||||||
<a href="#">Перейти</a>
|
<a href="/catalog/?sale=1">Перейти</a>
|
||||||
</div>
|
</div>
|
||||||
{# <img src="{% static 'img/kitchen-banner.jpg' %}" alt="">#}
|
{# <img src="{% static 'img/kitchen-banner.jpg' %}" alt="">#}
|
||||||
</section>
|
</section>
|
||||||
@@ -25,6 +25,9 @@
|
|||||||
<section class="auth-panel" aria-labelledby="login-title">
|
<section class="auth-panel" aria-labelledby="login-title">
|
||||||
<form class="auth-form" action="" method="post">
|
<form class="auth-form" action="" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
{% if next_url %}
|
||||||
|
<input type="hidden" name="next" value="{{ next_url }}">
|
||||||
|
{% endif %}
|
||||||
{% if form.non_field_errors %}
|
{% if form.non_field_errors %}
|
||||||
<div class="auth-alert auth-alert--error">
|
<div class="auth-alert auth-alert--error">
|
||||||
{% for error in form.non_field_errors %}
|
{% for error in form.non_field_errors %}
|
||||||
|
|||||||
@@ -69,6 +69,43 @@ class UserAuthFlowTests(TestCase):
|
|||||||
self.assertRedirects(response, reverse("users:profile"))
|
self.assertRedirects(response, reverse("users:profile"))
|
||||||
self.assertEqual(int(self.client.session["_auth_user_id"]), user.pk)
|
self.assertEqual(int(self.client.session["_auth_user_id"]), user.pk)
|
||||||
|
|
||||||
|
def test_login_redirects_to_safe_next_url(self):
|
||||||
|
user = User.objects.create_user(
|
||||||
|
username="cart-user",
|
||||||
|
email="cart-user@example.com",
|
||||||
|
password="StrongPassword123",
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
next_url = reverse("orders:cart")
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
f"{reverse('users:login')}?next={next_url}",
|
||||||
|
data={"email": "cart-user@example.com", "password": "StrongPassword123", "next": next_url},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRedirects(response, next_url)
|
||||||
|
self.assertEqual(int(self.client.session["_auth_user_id"]), user.pk)
|
||||||
|
|
||||||
|
def test_login_ignores_unsafe_next_url(self):
|
||||||
|
user = User.objects.create_user(
|
||||||
|
username="safe-user",
|
||||||
|
email="safe-user@example.com",
|
||||||
|
password="StrongPassword123",
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
f"{reverse('users:login')}?next=https://example.com/phishing",
|
||||||
|
data={
|
||||||
|
"email": "safe-user@example.com",
|
||||||
|
"password": "StrongPassword123",
|
||||||
|
"next": "https://example.com/phishing",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse("users:profile"))
|
||||||
|
self.assertEqual(int(self.client.session["_auth_user_id"]), user.pk)
|
||||||
|
|
||||||
def test_login_with_email_works_when_username_differs(self):
|
def test_login_with_email_works_when_username_differs(self):
|
||||||
user = User.objects.create_user(
|
user = User.objects.create_user(
|
||||||
username="oleg-old",
|
username="oleg-old",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from django.contrib.auth.views import (
|
|||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.http import urlsafe_base64_decode
|
from django.utils.http import url_has_allowed_host_and_scheme, urlsafe_base64_decode
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
|
|
||||||
from users.forms import LoginForm, ProfileForm, RegisterForm, SantehRayPasswordResetForm, SantehRaySetPasswordForm
|
from users.forms import LoginForm, ProfileForm, RegisterForm, SantehRayPasswordResetForm, SantehRaySetPasswordForm
|
||||||
@@ -22,17 +22,30 @@ User = get_user_model()
|
|||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
def _get_safe_next_url(request):
|
||||||
|
next_url = request.POST.get("next") or request.GET.get("next")
|
||||||
|
if next_url and url_has_allowed_host_and_scheme(
|
||||||
|
url=next_url,
|
||||||
|
allowed_hosts={request.get_host()},
|
||||||
|
require_https=request.is_secure(),
|
||||||
|
):
|
||||||
|
return next_url
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@require_http_methods(["GET", "POST"])
|
@require_http_methods(["GET", "POST"])
|
||||||
def login(request):
|
def login(request):
|
||||||
|
next_url = _get_safe_next_url(request)
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
return redirect("users:profile")
|
return redirect(next_url or "users:profile")
|
||||||
|
|
||||||
form = LoginForm(request=request, data=request.POST or None)
|
form = LoginForm(request=request, data=request.POST or None)
|
||||||
if request.method == "POST" and form.is_valid():
|
if request.method == "POST" and form.is_valid():
|
||||||
auth_login(request, form.get_user())
|
auth_login(request, form.get_user())
|
||||||
return redirect("users:profile")
|
return redirect(next_url or "users:profile")
|
||||||
|
|
||||||
return render(request, "users/login.html", context={"form": form})
|
return render(request, "users/login.html", context={"form": form, "next_url": next_url})
|
||||||
|
|
||||||
|
|
||||||
@require_http_methods(["GET", "POST"])
|
@require_http_methods(["GET", "POST"])
|
||||||
|
|||||||
Reference in New Issue
Block a user