2025-12-08 14:49:13 +03:00

260 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.http import HttpResponse, HttpResponseNotFound
from .models import *
from django.shortcuts import render, redirect
from django.contrib import messages
from .models import CallbackRequest # Импортируем из models, а не forms
from .forms import CallbackForm
from django.utils import timezone
from datetime import timedelta
from .models import PageView, Visitor
from django.db.models import Count
from django.contrib.auth.decorators import login_required, user_passes_test
from django.views.decorators.http import require_GET
menu = [
{'title': "Главная", 'url_name': 'home'},
{'title': "Проекты", 'url_name': 'solution'},
{'title': "Компетенции", 'url_name': 'ability'},
{'title': "Отзывы", 'url_name': 'recall'},
{'title': "Обо мне", 'url_name': 'about'}
]
# === ДОБАВЬТЕ ЭТИ ФУНКЦИИ ЗДЕСЬ ===
def get_client_ip(request):
"""Получаем реальный IP клиента"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
def should_track_request(request):
"""Определяем, нужно ли отслеживать запрос"""
client_ip = get_client_ip(request)
path = request.path
# Игнорируемые пути (Nextcloud специфичные)
nextcloud_paths = [
'/index.php',
'/status.php',
'/cron',
'/remote.php',
'/ocs',
'/apps/',
'/custom_apps/',
]
# Игнорируемые IP (Docker сети)
docker_ips = [
'192.168.64.1',
'192.168.65.1',
'172.17.0.1',
'172.18.0.1',
'172.19.0.1',
]
# Игнорируем статические файлы и админку
if path.startswith('/static/') or path.startswith('/admin/'):
return False
# Не отслеживаем Nextcloud и Docker запросы
if any(path.startswith(p) for p in nextcloud_paths):
return False
if client_ip in docker_ips:
return False
return True
def track_page_view(request):
"""Основная функция отслеживания просмотров"""
if not should_track_request(request):
return
try:
PageView.objects.create(
url=request.path,
ip_address=get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', '')[:500],
referer=request.META.get('HTTP_REFERER', '')[:500],
)
except Exception as e:
print(f"Error tracking page: {e}")
def track_view(view_func):
"""Декоратор для отслеживания просмотров страниц"""
from functools import wraps
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
# Отслеживаем просмотр перед выполнением view
track_page_view(request)
return view_func(request, *args, **kwargs)
return _wrapped_view
@track_view
def index(request):
posts = Home.objects.filter(is_published=True)
context = {
'posts': posts,
'menu': menu,
'title': "Программист 1С Николай Сердюк - разработка и сопровождение",
'meta_description': "Профессиональный программист 1С с более чем 10-летним опытом. Разработка, доработка, обновление и интеграция систем 1С. Сопровождение 1С.",
'meta_keywords': "программист 1С, разработка 1С, обновление 1С, сопровождение 1С, интеграция 1С, доработка 1С, 1С предприятие 8.3",
'form': CallbackForm()
}
return render(request, 'programmer/index.html', context=context)
@track_view
def about(request):
context = {
'menu': menu,
'title': "Программист 1С Николай Сердюк - 10+ лет опыта | Услуги 1С",
'meta_description': "Николай Сердюк - сертифицированный программист 1С с 10+ лет опыта. Специализация: обновление 1С, разработка под ключ, интеграция, миграция с 1С 7.7.",
'meta_keywords': "программист 1С Николай Сердюк, обновление 1С, разработка 1С под ключ, интеграция 1С, сертифицированный 1С, миграция 1С 7.7"
}
return render(request, 'programmer/about.html', context=context)
@track_view
def solution(request):
posts = Solution.objects.filter(is_published=True)
context = {
'posts': posts,
'menu': menu,
'meta_description': "Реализованные проекты по автоматизации 1С: складской учет с ТСД, интеграция с оборудованием, миграция с 1С 7.7. Примеры работ и кейсы.",
'meta_keywords': "проекты 1С, автоматизация склада 1С, интеграция ТСД 1С, миграция 1С 7.7, кейсы 1С, примеры работ 1С",
'title': "Проекты автоматизации 1С | Реализованные кейсы и решения",
}
return render(request, 'programmer/solution.html', context=context)
@track_view
def ability(request):
posts = Competence.objects.filter(is_published=True)
context = {
'posts': posts,
'menu': menu,
'title': "Сертификаты и компетенции 1С | Программист 1С Николай Сердюк",
'meta_description': "Сертификаты 1С: Профессионал по платформе 8.3 и БП 3.0. Подтвержденная квалификация программиста 1С с сертификатами фирмы 1С.",
'meta_keywords': "сертификаты 1С, 1С профессионал, компетенции 1С, квалификация программиста 1С, сертифицированный специалист 1С"
}
return render(request, 'programmer/competence.html', context=context)
@track_view
def recall(request):
posts = Recall.objects.filter(is_published=True)
context = {
'posts': posts,
'menu': menu,
'title': "Отзывы клиентов о работе программиста 1С | Реальные кейсы",
'meta_description': "Реальные отзывы клиентов о работе программиста 1С Николая Сердюка. Отзывы от ООО «РОВЕН-Регионы» и других компаний.",
'meta_keywords': "отзывы программист 1С, рекомендации 1С, отзывы клиентов 1С, реальные кейсы 1С, отзыв ООО РОВЕН"
}
return render(request, 'programmer/recall.html', context=context)
def show_post(request, post_id):
return HttpResponse(f"Отображение № {post_id}")
def pageNotFound(request, exception):
return HttpResponseNotFound('<h1>Страница не найдена</h1>')
def callback_request(request):
if request.method == 'POST':
form = CallbackForm(request.POST)
if form.is_valid():
# Сохраняем заявку через форму
form.save()
messages.success(request, '✅ Ваша заявка успешно отправлена! Я свяжусь с вами в ближайшее время.')
return redirect('home')
else:
# Если форма невалидна, показываем ошибки
for field, errors in form.errors.items():
for error in errors:
messages.error(request, f'❌ Ошибка в поле {form.fields[field].label}: {error}')
return redirect('home')
# Если GET запрос, просто показываем главную страницу
return redirect('home')
def is_admin(user):
return user.is_staff
def is_staff(user):
return user.is_staff
@login_required
@user_passes_test(is_staff)
def statistics_view(request):
today = timezone.now().date()
week_ago = today - timedelta(days=7)
# Статистика за сегодня
today_views = PageView.objects.filter(
timestamp__date=today
).count()
# Статистика за неделю
weekly_views = PageView.objects.filter(
timestamp__date__gte=week_ago
).count()
# Всего просмотров
total_views = PageView.objects.count()
# Популярные страницы за неделю
popular_pages = PageView.objects.filter(
timestamp__date__gte=week_ago
).values('url').annotate(
views=Count('id')
).order_by('-views')[:10]
# Уникальные посетители за неделю
unique_visitors = Visitor.objects.filter(
last_visit__date__gte=week_ago
).count()
# Последние посещения
recent_views = PageView.objects.select_related().order_by('-timestamp')[:20]
today = timezone.now().date()
total_callbacks = CallbackRequest.objects.count()
today_callbacks = CallbackRequest.objects.filter(time_create__date=today).count()
unread_callbacks = CallbackRequest.objects.filter(is_read=False).count()
context = {
'today_views': today_views,
'weekly_views': weekly_views,
'total_views': total_views,
'unique_visitors': unique_visitors,
'popular_pages': popular_pages,
'recent_views': recent_views,
'total_callbacks': total_callbacks,
'today_callbacks': today_callbacks,
'unread_callbacks': unread_callbacks,
}
return render(request, 'admin/statistics.html', context)
@require_GET
def robots_txt(request):
return render(request, 'robots.txt', content_type='text/plain')