diff --git a/oknardia/templates/popup/popup_index.html b/oknardia/templates/popup/popup_index.html
index d430198..af285cc 100755
--- a/oknardia/templates/popup/popup_index.html
+++ b/oknardia/templates/popup/popup_index.html
@@ -75,11 +75,7 @@
- {% if LAST_VISIT %}
Ваши последние просмотры:
-
-
{% endif %}
+ {% include 'report/report_last_user_visit.html' with background_color="None" %}
{% endwith %}
\ No newline at end of file
diff --git a/oknardia/templates/price/price_list.html b/oknardia/templates/price/price_list.html
index 444075b..ac5a178 100755
--- a/oknardia/templates/price/price_list.html
+++ b/oknardia/templates/price/price_list.html
@@ -107,7 +107,8 @@
{% endblock %}
-{% block Top_JS3%}
+
diff --git a/oknardia/web/catalog.py b/oknardia/web/catalog.py
index b09f747..484b326 100644
--- a/oknardia/web/catalog.py
+++ b/oknardia/web/catalog.py
@@ -7,7 +7,7 @@ from django.shortcuts import render, redirect
from oknardia.models import Seria_Info, SetKit
from web.add_func import get_rating_set_for_stars
-from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
+from web.report1 import get_last_all_user_visit_list, get_last_user_visit_list
def catalog_root(request: HttpRequest) -> HttpResponse:
@@ -21,7 +21,6 @@ def catalog_root(request: HttpRequest) -> HttpResponse:
time_start = time.perf_counter()
# получаем из cookies последние визиты клиента
to_template: dict[str, object] = {
- 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)}
response = render(request, "catalog/catalog_root.html", to_template)
@@ -83,7 +82,6 @@ def catalog_sets(request: HttpRequest) -> HttpResponse:
to_template: dict[str, object] = {
'SET_LIST': kits,
- 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start),
}
diff --git a/oknardia/web/catalog_companies.py b/oknardia/web/catalog_companies.py
index b4f448a..8d0005b 100644
--- a/oknardia/web/catalog_companies.py
+++ b/oknardia/web/catalog_companies.py
@@ -17,11 +17,7 @@ from oknardia.models import (
SetKit,
PriceOffer,
)
-from web.report1 import (
- get_last_all_user_visit_list,
- get_last_user_visit_cookies,
- get_last_user_visit_list
-)
+from web.report1 import get_last_all_user_visit_list, get_last_user_visit_list
from web.add_func import get_rating_set_for_stars
import django.utils.dateformat
import time
@@ -179,7 +175,6 @@ def catalog_company(request: HttpRequest) -> HttpResponse:
Контекст шаблона:
- COMPANIES (list): Список компаний с статистикой
- - LAST_VISIT (list): Последние визиты текущего пользователя
- LOG_VISIT (list): Последние визиты всех пользователей
Args:
@@ -200,9 +195,6 @@ def catalog_company(request: HttpRequest) -> HttpResponse:
# Получаем информацию о посещениях для персонализации
to_template: dict[str, object] = {
'COMPANIES': formatted_companies,
- 'LAST_VISIT': get_last_user_visit_list(
- get_last_user_visit_cookies(request)[:3]
- ),
'LOG_VISIT': get_last_all_user_visit_list(),
}
@@ -469,7 +461,6 @@ def catalog_company_detail(
- SETS (list): Список оконных наборов с их полной информацией
- IMG_FOR_BLOG (str): Логотип компании
- LIST_NOT (list): Стандартные маркеры "пусто"
- - LAST_VISIT (list): Последние визиты текущего пользователя
- LOG_VISIT (list): Последние визиты всех пользователей
- ticks (float): Время выполнения представления (в секундах)
@@ -518,9 +509,6 @@ def catalog_company_detail(
'META_KEYWORDS': company.sMerchantName,
'IMG_FOR_BLOG': company.pMerchantLogo,
'LIST_NOT': empty_values,
- 'LAST_VISIT': get_last_user_visit_list(
- get_last_user_visit_cookies(request)[:3]
- ),
'LOG_VISIT': get_last_all_user_visit_list(),
}
diff --git a/oknardia/web/catalog_openings.py b/oknardia/web/catalog_openings.py
index 5c9eefd..e5bced4 100644
--- a/oknardia/web/catalog_openings.py
+++ b/oknardia/web/catalog_openings.py
@@ -3,7 +3,7 @@ from django.db.models import F
from django.shortcuts import render
from django.http import HttpRequest, HttpResponse
from oknardia.models import MountDim2Apartment
-from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
+from web.report1 import get_last_all_user_visit_list, get_last_user_visit_list
from web.add_func import get_flaps_for_mini_pictures
import time
import pytils
@@ -20,8 +20,6 @@ def _make_slug(value: str) -> str:
def _append_visit_context(to_template: dict, request: HttpRequest, time_start: float) -> None:
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
to_template.update({
- # получаем последние визиты клиента через куки
- 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start),
diff --git a/oknardia/web/catalog_profiles.py b/oknardia/web/catalog_profiles.py
index d19dbe5..fa70c4f 100644
--- a/oknardia/web/catalog_profiles.py
+++ b/oknardia/web/catalog_profiles.py
@@ -7,7 +7,7 @@ from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from oknardia.settings import *
from oknardia.models import Catalog2Profile, PVCprofiles, PriceOffer
-from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
+from web.report1 import get_last_all_user_visit_list, get_last_user_visit_list
from web.add_func import normalize, get_rating_set_for_stars
import time
import json
@@ -49,7 +49,6 @@ def _profile_row_to_dict(profile: dict) -> dict:
def _append_visit_context(to_template: dict, request: HttpRequest, time_start: float) -> None:
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
to_template.update({
- 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start),
})
diff --git a/oknardia/web/catalog_series.py b/oknardia/web/catalog_series.py
index 2c46124..77129d0 100644
--- a/oknardia/web/catalog_series.py
+++ b/oknardia/web/catalog_series.py
@@ -13,7 +13,7 @@ from oknardia.models import (
Win_MountDim,
Building_Info,
)
-from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
+from web.report1 import get_last_all_user_visit_list, get_last_user_visit_list
from web.add_func import get_flaps_for_big_pictures
import time
import os
@@ -29,7 +29,6 @@ def _make_slug(value: str) -> str:
def _append_visit_context(to_template: dict, request: HttpRequest, time_start: float) -> None:
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
to_template.update({
- 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start),
})
diff --git a/oknardia/web/prices.py b/oknardia/web/prices.py
index 4c78c0c..57e0ce6 100644
--- a/oknardia/web/prices.py
+++ b/oknardia/web/prices.py
@@ -14,7 +14,7 @@ from oknardia.models import (
MountDim2Apartment,
)
from oknardia.settings import *
-from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
+from web.report1 import get_last_all_user_visit_list, get_last_user_visit_list
from web.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures, get_flaps_for_mini_pictures, \
get_geo_distance
import django.utils.dateformat
@@ -57,11 +57,8 @@ def _append_visit_context(
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
if log_visit is None:
log_visit = get_last_all_user_visit_list()
- if last_visit_cookie is None:
- last_visit_cookie = get_last_user_visit_cookies(request)
to_template.update({
- 'LAST_VISIT': get_last_user_visit_list(last_visit_cookie[:3]),
'LOG_VISIT': log_visit,
'ticks': float(time.perf_counter() - time_start),
})
@@ -956,29 +953,14 @@ def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str =
)
log_entry.save() # INSERT
- # получаем последние визиты клиента через куки
- last_visit = get_last_user_visit_cookies(request)
- # Для блока LAST_VISIT показываем историю до текущего захода.
- last_visit_for_context = list(last_visit)
- # подготавливаем данные о текущем посещении для помещения в cookie
- Item = {
- "LastURL": new_url,
- "LastAddress": to_template["ADDRESS"],
- "LastApart": to_template["APART"],
- "Time": time.perf_counter()}
- last_visit.insert(0, Item) # Добавляем текущий Item в начало
- last_visit = json.dumps(last_visit[:3]) # упаковываем json без пробелов (три записи)
- # print u"сейчас запишем вот эту куку:", LastVisit
+ # Вызываем контекст без параметра last_visit_cookie (получит из кук автоматически)
_append_visit_context(
to_template=to_template,
request=request,
time_start=time_start,
log_visit=log_visit,
- last_visit_cookie=last_visit_for_context,
)
- response = render(request, "price/price_list.html", to_template)
- response.set_cookie("LastVisit", last_visit, max_age=7862400) # ставим или перезаписываем куки (91 день)
- return response
+ return render(request, "price/price_list.html", to_template)
def next_price_frame(request: HttpRequest, apart_id: str = "1", mount_dim_per_offer: str = "1",
diff --git a/oknardia/web/report1.py b/oknardia/web/report1.py
index c394f31..5818843 100644
--- a/oknardia/web/report1.py
+++ b/oknardia/web/report1.py
@@ -95,21 +95,6 @@ def _bounds(items: list, field: str, threshold=None) -> tuple[float, float]:
return min(vals), max(vals)
-def get_last_user_visit_cookies(request: HttpRequest) -> list:
- """ Служебная функция: проверяет есть ли куки о последних посещениях пользователя, и если есть возвращает их
-
- :param request: HttpRequest -- входящий http-запрос
- :return LastVisit: json -- загруженный json-объект из куки LastVisit
- """
- if "LastVisit" in request.COOKIES:
- try:
- return json.loads(request.COOKIES["LastVisit"])
- except (json.decoder.JSONDecodeError, TypeError, ValueError, KeyError, AttributeError):
- return []
- else:
- return []
-
-
def get_last_user_visit_list(list_visit: list) -> list:
""" Служебная функция: получает список с посещенных страниц с ценовой выдачей (ListVisit), меняет в нем даты
на описание типа "три недели назад" и возвращает обратно.
@@ -417,10 +402,7 @@ def compare_offers(request: HttpRequest, to_compare: str = "1,2") -> HttpRespons
except SetKit.DoesNotExist:
pass
to_template.update({
- # получаем последние визиты клиента через куки
- 'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
- # id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
diff --git a/oknardia/web/test_prices.py b/oknardia/web/test_prices.py
index c7e8e2d..596f43e 100644
--- a/oknardia/web/test_prices.py
+++ b/oknardia/web/test_prices.py
@@ -158,9 +158,6 @@ class ReportOneWinPriceTests(TestCase):
sOfferActive=False,
)
- @patch("web.prices.get_last_all_user_visit_list", return_value=[])
- @patch("web.prices.get_last_user_visit_list", return_value=[])
- @patch("web.prices.get_last_user_visit_cookies", return_value=[])
@patch("web.prices.get_flaps_for_mini_pictures", return_value="img/test-mini.png")
@patch(
"web.prices.get_flaps_for_big_pictures",
@@ -178,9 +175,6 @@ class ReportOneWinPriceTests(TestCase):
self,
mocked_big_pictures,
mocked_mini_pictures,
- mocked_cookies,
- mocked_last_visits,
- mocked_all_visits,
):
"""Вьюха должна собирать тот же ключевой контекст, но уже без raw SQL."""
request = self.factory.get(
@@ -216,9 +210,6 @@ class ReportOneWinPriceTests(TestCase):
self.assertIn("META_DATA_PUBLISH", context)
self.assertTrue(mocked_big_pictures.called)
self.assertTrue(mocked_mini_pictures.called)
- self.assertTrue(mocked_cookies.called)
- self.assertTrue(mocked_last_visits.called)
- self.assertTrue(mocked_all_visits.called)
def test_report_one_win_price_redirects_to_canonical_dimensions(self):
"""Если SEO-размеры в URL неверные, вьюха должна редиректить на канонический URL."""
diff --git a/oknardia/web/tests.py b/oknardia/web/tests.py
index 0dfef8f..79209a1 100644
--- a/oknardia/web/tests.py
+++ b/oknardia/web/tests.py
@@ -156,14 +156,8 @@ class CatalogProfileViewTests(TestCase):
return profile, sibling, brand, blog
- @patch("web.catalog.get_last_all_user_visit_list", return_value=["all-visits"])
- @patch("web.catalog.get_last_user_visit_list", return_value=["last-visits"])
- @patch("web.catalog.get_last_user_visit_cookies", return_value=["cookie-1", "cookie-2", "cookie-3"])
def test_catalog_profile_handles_empty_catalog(
self,
- mocked_cookies,
- mocked_last_visits,
- mocked_all_visits,
):
"""Пустой каталог не должен падать и должен отдавать ожидаемый контекст."""
with self.assertNumQueries(1):
@@ -174,20 +168,10 @@ class CatalogProfileViewTests(TestCase):
self.assertEqual(context["CATALOG_PROFILE_NUM"], "0 профилей")
self.assertEqual(context["CATALOG_MANUFACT_NUM"], 0)
self.assertEqual(context["CATALOG_PROFILE_MAN1_NAME2"], [])
- self.assertEqual(context["LAST_VISIT"], ["last-visits"])
- self.assertEqual(context["LOG_VISIT"], ["all-visits"])
- self.assertTrue(mocked_cookies.called)
- self.assertTrue(mocked_last_visits.called)
- self.assertTrue(mocked_all_visits.called)
- @patch("web.catalog.get_last_all_user_visit_list", return_value=[])
- @patch("web.catalog.get_last_user_visit_list", return_value=[])
- @patch("web.catalog.get_last_user_visit_cookies", return_value=[])
+
def test_catalog_profile_groups_and_sorts_profiles(
self,
- mocked_cookies,
- mocked_last_visits,
- mocked_all_visits,
):
"""Каталог должен группировать профили по производителю и сохранять сортировку."""
self._create_profile(name="Alpha Basic", brief="Альфа База", manufacturer="Альфа", days_ago=5)
@@ -224,20 +208,9 @@ class CatalogProfileViewTests(TestCase):
# Проверяем итоговые счетчики и структуру контекста.
self.assertEqual(context["CATALOG_MANUFACT_NUM"], 2)
self.assertEqual(context["CATALOG_PROFILE_NUM"], "4 профиля")
- self.assertEqual(context["LAST_VISIT"], [])
- self.assertEqual(context["LOG_VISIT"], [])
- self.assertTrue(mocked_cookies.called)
- self.assertTrue(mocked_last_visits.called)
- self.assertTrue(mocked_all_visits.called)
- @patch("web.catalog.get_last_all_user_visit_list", return_value=[])
- @patch("web.catalog.get_last_user_visit_list", return_value=[])
- @patch("web.catalog.get_last_user_visit_cookies", return_value=[])
def test_catalog_profile_model_redirects_to_canonical_url(
self,
- mocked_cookies,
- mocked_last_visits,
- mocked_all_visits,
):
"""При неверных slug страница должна отправлять на канонический URL."""
profile = self._create_profile(name="Alpha Basic", brief="Альфа База", manufacturer="Альфа", days_ago=5)
@@ -248,14 +221,8 @@ class CatalogProfileViewTests(TestCase):
self.assertEqual(response.status_code, 302)
self.assertEqual(response["Location"], f"/catalog/profile/{profile.id}-alfa/{profile.id}-alpha-basic")
- @patch("web.catalog.get_last_all_user_visit_list", return_value=[])
- @patch("web.catalog.get_last_user_visit_list", return_value=[])
- @patch("web.catalog.get_last_user_visit_cookies", return_value=[])
def test_catalog_profile_model_renders_related_data(
self,
- mocked_cookies,
- mocked_last_visits,
- mocked_all_visits,
):
"""Карточка профиля должна собираться через ORM и отдавать все ключевые блоки."""
profile, sibling, brand, blog = self._create_catalog_profile_model_fixture()
@@ -287,7 +254,4 @@ class CatalogProfileViewTests(TestCase):
self.assertEqual(context["IMG_FOR_BLOG"], blog.sImgForBlogSocial)
self.assertEqual(context["PUB_DAT"].date(), blog.dPostDataModify.date())
self.assertEqual(context["LIST_OTHER"], ["Контур:2", "Цвет:Белый"])
- self.assertTrue(mocked_cookies.called)
- self.assertTrue(mocked_last_visits.called)
- self.assertTrue(mocked_all_visits.called)
diff --git a/oknardia/web/views.py b/oknardia/web/views.py
index f3ca3de..edfe6e3 100644
--- a/oknardia/web/views.py
+++ b/oknardia/web/views.py
@@ -16,7 +16,7 @@ import pytils
def main_init(request: HttpRequest) -> HttpResponse:
- """ Главная страница (статичная, только с проверками куков)
+ """ Главная страница (статичная, только с проверками кук)
:param request: входящий http-запрос
:return response: исходящий http-ответ
@@ -28,22 +28,6 @@ def main_init(request: HttpRequest) -> HttpResponse:
# стоят куки, и это не первый визит
num_viz = request.COOKIES["NumVisit"] # читаем число визитов
num_viz = int(num_viz) + 1 # увеличиваем порядковый номер визитов
- # ПРОВЕРЯЧЕМ КУКИ ПРОСМОТРЕ ЦЕНОВЫХ ПРЕДЛОЖЕНИЙ
- if "LastVisit" in request.COOKIES:
- # стоят куки
- last_visit = json.loads(request.COOKIES["LastVisit"])
- last_visit2 = []
- for i in last_visit:
- last_visit2.append({
- "Time": datetime.datetime.fromtimestamp(i["Time"]),
- "LastURL": i["LastURL"],
- "LastAddress": i["LastAddress"],
- "LastApart": i["LastApart"]
- })
- to_template.update({'LAST_VISIT': last_visit2[:3]})
- else:
- to_template.update({'LAST_VISIT': None})
- to_template.update({'META_DOCUMENT_STATE': u"Static"}) # Эта страничка статичная (в шаблон)
to_template.update({'NV': num_viz})
# to_template.update(csrf(request)) # токен, для метода POST и GET
response = render(request, "index.html", to_template)
diff --git a/public/static/js/track_user_visit.js b/public/static/js/track_user_visit.js
new file mode 100644
index 0000000..1776e8d
--- /dev/null
+++ b/public/static/js/track_user_visit.js
@@ -0,0 +1,98 @@
+/**
+ * Логика записи визитов пользователя в cookies.
+ * Отслеживает последние посещения страниц с ценовой выдачей.
+ *
+ * Используемые данные из HTML:
+ * - data-current-url: текущий URL страницы
+ * - data-address: адрес здания
+ * - data-apart: тип квартиры
+ *
+ * Сохраняет в куку 'LastVisit' максимум 3 последних визита в формате JSON.
+ */
+
+function trackUserVisit(currentUrl, address, apart) {
+ // Функция для получения значения куки по имени
+ function getCookieValue(name) {
+ try {
+ if (document.cookie) {
+ const cookies = document.cookie.split('; ');
+ for (let cookie of cookies) {
+ const [cookieName, cookieValue] = cookie.split('=');
+ if (cookieName === name) {
+ return decodeURIComponent(cookieValue);
+ }
+ }
+ }
+ } catch (e) {
+ console.warn('Ошибка при чтении куки:', e);
+ }
+ return null;
+ }
+
+ // Функция для установки куки с заданным сроком жизни
+ function setCookie(name, value, maxAge) {
+ try {
+ const cookieValue = encodeURIComponent(value);
+ let cookieString = `${name}=${cookieValue}; path=/`;
+ if (maxAge) {
+ cookieString += `; max-age=${maxAge}`;
+ }
+ document.cookie = cookieString;
+ } catch (e) {
+ console.warn('Ошибка при установке куки:', e);
+ }
+ }
+
+ // Получаем последние визиты из куки (если есть)
+ let lastVisits = [];
+ const cookieValue = getCookieValue('LastVisit');
+ if (cookieValue) {
+ try {
+ lastVisits = JSON.parse(cookieValue);
+ } catch (e) {
+ console.warn('Ошибка при разборе JSON из куки LastVisit:', e);
+ lastVisits = [];
+ }
+ }
+
+ // Создаём новый item посещения с текущей информацией
+ const newItem = {
+ LastURL: currentUrl,
+ LastAddress: address,
+ LastApart: apart,
+ Time: performance.now() // используем performance.now() как аналог time.perf_counter() в Python
+ };
+
+ // Добавляем новый item в начало списка
+ lastVisits.unshift(newItem);
+
+ // Оставляем максимум 3 последних записи
+ lastVisits = lastVisits.slice(0, 4);
+
+ // Упаковываем в JSON (JSON.stringify без пробелов для компактности)
+ const jsonData = JSON.stringify(lastVisits);
+
+ // Устанавливаем куки на 91 день (7862400 секунд)
+ setCookie('LastVisit', jsonData, 7862400);
+}
+
+/**
+ * Инициализация отслеживания при загрузке документа.
+ * Ищет элемент с атрибутами data-current-url, data-address, data-apart
+ * и вызывает trackUserVisit с полученными значениями.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ // Ищем элемент со встроенными данными (например, скрытый div в шаблоне)
+ const trackingElement = document.querySelector('[data-current-url]');
+
+ if (trackingElement) {
+ const currentUrl = trackingElement.getAttribute('data-current-url');
+ const address = trackingElement.getAttribute('data-address');
+ const apart = trackingElement.getAttribute('data-apart');
+
+ if (currentUrl && address && apart) {
+ trackUserVisit(currentUrl, address, apart);
+ }
+ }
+});
+