diff --git a/.gitignore b/.gitignore index 161feaf..1e69eed 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,9 @@ ENV/ # OS .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db + +# Project specific +*.log +*.pot +*.py[co] \ No newline at end of file diff --git a/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc b/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc deleted file mode 100644 index e572069..0000000 Binary files a/OneCprogsite/OneCprogsite/__pycache__/settings.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/OneCprogsite/__pycache__/urls.cpython-310.pyc b/OneCprogsite/OneCprogsite/__pycache__/urls.cpython-310.pyc deleted file mode 100644 index 382208c..0000000 Binary files a/OneCprogsite/OneCprogsite/__pycache__/urls.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/OneCprogsite/__pycache__/wsgi.cpython-310.pyc b/OneCprogsite/OneCprogsite/__pycache__/wsgi.cpython-310.pyc deleted file mode 100644 index ebfdfae..0000000 Binary files a/OneCprogsite/OneCprogsite/__pycache__/wsgi.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc deleted file mode 100644 index 38271a2..0000000 Binary files a/OneCprogsite/programmer/__pycache__/admin.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/apps.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/apps.cpython-310.pyc deleted file mode 100644 index 1bc3cb6..0000000 Binary files a/OneCprogsite/programmer/__pycache__/apps.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/context_processors.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/context_processors.cpython-310.pyc deleted file mode 100644 index bb6b4c0..0000000 Binary files a/OneCprogsite/programmer/__pycache__/context_processors.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/forms.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/forms.cpython-310.pyc deleted file mode 100644 index 8fdc086..0000000 Binary files a/OneCprogsite/programmer/__pycache__/forms.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/middleware.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/middleware.cpython-310.pyc deleted file mode 100644 index 9fc794e..0000000 Binary files a/OneCprogsite/programmer/__pycache__/middleware.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc deleted file mode 100644 index 90f1ff9..0000000 Binary files a/OneCprogsite/programmer/__pycache__/models.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/sitemaps.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/sitemaps.cpython-310.pyc deleted file mode 100644 index 46831ac..0000000 Binary files a/OneCprogsite/programmer/__pycache__/sitemaps.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc deleted file mode 100644 index b007e84..0000000 Binary files a/OneCprogsite/programmer/__pycache__/urls.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc b/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc deleted file mode 100644 index 3c4cca7..0000000 Binary files a/OneCprogsite/programmer/__pycache__/views.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0001_initial.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0001_initial.cpython-310.pyc deleted file mode 100644 index 09854a6..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0001_initial.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0002_alter_competence_options_alter_competence_content_and_more.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0002_alter_competence_options_alter_competence_content_and_more.cpython-310.pyc deleted file mode 100644 index db34b31..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0002_alter_competence_options_alter_competence_content_and_more.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0003_recall_rename_is_publiched_competence_is_published.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0003_recall_rename_is_publiched_competence_is_published.cpython-310.pyc deleted file mode 100644 index b43c27b..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0003_recall_rename_is_publiched_competence_is_published.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0004_rename_photo_recall_scan.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0004_rename_photo_recall_scan.cpython-310.pyc deleted file mode 100644 index 474f4a1..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0004_rename_photo_recall_scan.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0005_auto_20231124_1519.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0005_auto_20231124_1519.cpython-310.pyc deleted file mode 100644 index b626d01..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0005_auto_20231124_1519.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0006_alter_recall_scan.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0006_alter_recall_scan.cpython-310.pyc deleted file mode 100644 index caac6b8..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0006_alter_recall_scan.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0007_solution.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0007_solution.cpython-310.pyc deleted file mode 100644 index 90cdd6f..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0007_solution.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0008_home.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0008_home.cpython-310.pyc deleted file mode 100644 index 20cebcb..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0008_home.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0009_callbackrequest_alter_competence_options.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0009_callbackrequest_alter_competence_options.cpython-310.pyc deleted file mode 100644 index 2c3bab4..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0009_callbackrequest_alter_competence_options.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0010_alter_callbackrequest_email_and_more.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0010_alter_callbackrequest_email_and_more.cpython-310.pyc deleted file mode 100644 index 165fc95..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0010_alter_callbackrequest_email_and_more.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0011_visitor_pageview.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0011_visitor_pageview.cpython-310.pyc deleted file mode 100644 index b085443..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0011_visitor_pageview.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0012_callbackrequest_is_read.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0012_callbackrequest_is_read.cpython-310.pyc deleted file mode 100644 index 342d187..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0012_callbackrequest_is_read.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/migrations/__pycache__/0013_callbackrequest_notification_sent.cpython-310.pyc b/OneCprogsite/programmer/migrations/__pycache__/0013_callbackrequest_notification_sent.cpython-310.pyc deleted file mode 100644 index 1bbd4b6..0000000 Binary files a/OneCprogsite/programmer/migrations/__pycache__/0013_callbackrequest_notification_sent.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/templatetags/__pycache__/programmer_tags.cpython-310.pyc b/OneCprogsite/programmer/templatetags/__pycache__/programmer_tags.cpython-310.pyc deleted file mode 100644 index 2201004..0000000 Binary files a/OneCprogsite/programmer/templatetags/__pycache__/programmer_tags.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/templatetags/__pycache__/seo_tags.cpython-310.pyc b/OneCprogsite/programmer/templatetags/__pycache__/seo_tags.cpython-310.pyc deleted file mode 100644 index b8da77a..0000000 Binary files a/OneCprogsite/programmer/templatetags/__pycache__/seo_tags.cpython-310.pyc and /dev/null differ diff --git a/OneCprogsite/programmer/utils/__pycache__/email_notifications.cpython-310.pyc b/OneCprogsite/programmer/utils/__pycache__/email_notifications.cpython-310.pyc deleted file mode 100644 index 12f89e7..0000000 Binary files a/OneCprogsite/programmer/utils/__pycache__/email_notifications.cpython-310.pyc and /dev/null differ diff --git a/programmer/admin.py b/programmer/admin.py index b2a1f5c..5962719 100644 --- a/programmer/admin.py +++ b/programmer/admin.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from django.contrib import admin from django.utils import timezone from django.utils.html import format_html @@ -168,174 +167,3 @@ admin.site.register(Competence, ProgrammerAdmin) admin.site.register(Recall, RecallAdmin) admin.site.register(Solution, SolutionAdmin) admin.site.register(Home, HomeAdmin) -======= -from django.contrib import admin -from django.utils import timezone -from django.utils.html import format_html -from django.urls import path -from django.shortcuts import render -from django.http import HttpResponseRedirect -from django.contrib import messages -from .models import * - - -class ProgrammerAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'photo', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'content') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - - -class RecallAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'scan', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'content') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - - -class SolutionAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'description', 'implementation') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - - -class HomeAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'content') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - - -@admin.register(CallbackRequest) -class CallbackAdmin(admin.ModelAdmin): - list_display = ('name', 'phone', 'email', 'time_create', 'is_processed', 'is_read', 'new_badge') - list_display_links = ('name', 'phone') - list_editable = ('is_processed', 'is_read') - list_filter = ('time_create', 'is_processed', 'is_read') - search_fields = ('name', 'phone', 'email') - readonly_fields = ('time_create',) - actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed'] - actions = ['mark_as_read', 'mark_as_unread', 'mark_as_processed', 'resend_notification'] - - def resend_notification(self, request, queryset): - from .utils.email_notifications import send_callback_notification - count = 0 - for callback in queryset: - success = send_callback_notification(callback) - if success: - count += 1 - self.message_user(request, f'Уведомления отправлены для {count} заявок') - - resend_notification.short_description = "Переотправить email уведомления" - - def new_badge(self, obj): - if not obj.is_read: - return format_html('🆕 НОВАЯ') - return "" - - new_badge.short_description = 'Статус' - - def get_queryset(self, request): - # Показываем количество непрочитанных в заголовке - unread_count = CallbackRequest.objects.filter(is_read=False).count() - if unread_count > 0: - self.message_user( - request, - f'У вас {unread_count} непрочитанных заявок!', - messages.WARNING - ) - return super().get_queryset(request) - - def mark_as_read(self, request, queryset): - updated = queryset.update(is_read=True) - self.message_user(request, f'{updated} заявок отмечены как прочитанные') - - mark_as_read.short_description = "Отметить как прочитанные" - - def mark_as_unread(self, request, queryset): - updated = queryset.update(is_read=False) - self.message_user(request, f'{updated} заявок отмечены как непрочитанные') - - mark_as_unread.short_description = "Отметить как непрочитанные" - - def mark_as_processed(self, request, queryset): - updated = queryset.update(is_processed=True) - self.message_user(request, f'{updated} заявок отмечены как обработанные') - - mark_as_processed.short_description = "Отметить как обработанные" - - # Добавляем кастомное представление для статистики - def get_urls(self): - urls = super().get_urls() - custom_urls = [ - path('callback-stats/', self.admin_site.admin_view(self.callback_stats), name='callback_stats'), - ] - return custom_urls + urls - - def callback_stats(self, request): - today = timezone.now().date() - week_ago = today - timezone.timedelta(days=7) - - stats = { - 'total': CallbackRequest.objects.count(), - 'today': CallbackRequest.objects.filter(time_create__date=today).count(), - 'week': CallbackRequest.objects.filter(time_create__date__gte=week_ago).count(), - 'unread': CallbackRequest.objects.filter(is_read=False).count(), - 'unprocessed': CallbackRequest.objects.filter(is_processed=False).count(), - } - - context = { - **self.admin_site.each_context(request), - 'title': 'Статистика заявок', - 'stats': stats, - } - return render(request, 'admin/callback_stats.html', context) - -class ProgrammerAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'photo', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'content') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - -class RecallAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'scan', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'content') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - -class SolutionAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'description', 'implementation') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - -class HomeAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'time_create', 'is_published') - list_display_links = ('id', 'title') - search_fields = ('title', 'content') - list_editable = ('is_published',) - list_filter = ('time_create', 'is_published') - -@admin.register(PageView) -class PageViewAdmin(admin.ModelAdmin): - list_display = ['url', 'timestamp', 'ip_address'] - list_filter = ['timestamp', 'url'] - search_fields = ['url', 'ip_address'] - date_hierarchy = 'timestamp' - - def get_queryset(self, request): - return super().get_queryset(request).order_by('-timestamp') - -admin.site.register(Competence, ProgrammerAdmin) -admin.site.register(Recall, RecallAdmin) -admin.site.register(Solution, SolutionAdmin) -admin.site.register(Home, HomeAdmin) ->>>>>>> master diff --git a/programmer/apps.py b/programmer/apps.py index c2c4ad0..c8b6481 100644 --- a/programmer/apps.py +++ b/programmer/apps.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from django.apps import AppConfig @@ -6,12 +5,3 @@ class ProgrammerConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'programmer' verbose_name = 'Программисты' -======= -from django.apps import AppConfig - - -class ProgrammerConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'programmer' - verbose_name = 'Программисты' ->>>>>>> master diff --git a/programmer/context_processors.py b/programmer/context_processors.py index 7261401..41a7d3c 100644 --- a/programmer/context_processors.py +++ b/programmer/context_processors.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from .views import menu from django.conf import settings @@ -10,17 +9,4 @@ def contact_info(request): return { 'CONTACT_EMAIL': getattr(settings, 'CONTACT_EMAIL', 'it@nserdyuk.ru'), 'CONTACT_PHONE': getattr(settings, 'CONTACT_PHONE', '+7 (960) 469-40-88'), -======= -from .views import menu -from django.conf import settings - - -def menu_processor(request): - return {'menu': menu} - -def contact_info(request): - return { - 'CONTACT_EMAIL': getattr(settings, 'CONTACT_EMAIL', 'it@nserdyuk.ru'), - 'CONTACT_PHONE': getattr(settings, 'CONTACT_PHONE', '+7 (960) 469-40-88'), ->>>>>>> master } \ No newline at end of file diff --git a/programmer/forms.py b/programmer/forms.py index 9023bc1..9726b2c 100644 --- a/programmer/forms.py +++ b/programmer/forms.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from django import forms from .models import CallbackRequest @@ -31,38 +30,4 @@ class CallbackForm(forms.ModelForm): 'phone': 'Телефон', 'email': 'Электронная почта', 'question': 'Ваш вопрос' -======= -from django import forms -from .models import CallbackRequest - - -class CallbackForm(forms.ModelForm): - class Meta: - model = CallbackRequest - fields = ['name', 'phone', 'email', 'question'] - widgets = { - 'name': forms.TextInput(attrs={ - 'class': 'form-input', - 'placeholder': 'Ваше имя' - }), - 'phone': forms.TextInput(attrs={ - 'class': 'form-input', - 'placeholder': '+7 (___) ___-__-__' - }), - 'email': forms.EmailInput(attrs={ - 'class': 'form-input', - 'placeholder': 'your@email.com' - }), - 'question': forms.Textarea(attrs={ - 'class': 'form-textarea', - 'placeholder': 'Опишите ваш вопрос или задачу...', - 'rows': 4 - }), - } - labels = { - 'name': 'Имя', - 'phone': 'Телефон', - 'email': 'Электронная почта', - 'question': 'Ваш вопрос' ->>>>>>> master } \ No newline at end of file diff --git a/programmer/middleware.py b/programmer/middleware.py index 98e272c..494461e 100644 --- a/programmer/middleware.py +++ b/programmer/middleware.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from .models import PageView, Visitor from django.utils import timezone from django.db import transaction @@ -52,59 +51,4 @@ class PageViewMiddleware: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') -======= -from .models import PageView, Visitor -from django.utils import timezone -from django.db import transaction - - -class PageViewMiddleware: - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - # Игнорируем статические файлы и админку - if not request.path.startswith('/static/') and not request.path.startswith('/admin/'): - self.track_page_view(request) - - response = self.get_response(request) - return response - - def track_page_view(self, request): - try: - with transaction.atomic(): - # Сохраняем просмотр страницы - PageView.objects.create( - url=request.path, - ip_address=self.get_client_ip(request), - user_agent=request.META.get('HTTP_USER_AGENT', ''), - referer=request.META.get('HTTP_REFERER', '') - ) - - # Обновляем статистику посетителя - ip = self.get_client_ip(request) - visitor, created = Visitor.objects.get_or_create( - ip_address=ip, - defaults={ - 'first_visit': timezone.now(), - 'last_visit': timezone.now() - } - ) - - if not created: - visitor.last_visit = timezone.now() - visitor.visit_count += 1 - visitor.save() - - except Exception as e: - # Логируем ошибку, но не прерываем выполнение - print(f"Error tracking page view: {e}") - - def get_client_ip(self, request): - 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') ->>>>>>> master return ip \ No newline at end of file diff --git a/programmer/models.py b/programmer/models.py index e07c9a6..b62f79b 100644 --- a/programmer/models.py +++ b/programmer/models.py @@ -1,159 +1,3 @@ -<<<<<<< HEAD -from django.db import models -from django.urls import reverse -from django.utils import timezone -from django.db.models.signals import post_save, post_delete -from django.dispatch import receiver -from django.core.cache import cache -from .utils.email_notifications import send_callback_notification - - -class Recall(models.Model): - title = models.CharField(max_length=255, verbose_name='Организация') - content = models.TextField(blank=True, verbose_name='Отзыв') - scan = models.ImageField(upload_to="scan/%Y/%m/%d/", verbose_name='Фото') - time_create = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания') - time_update = models.DateTimeField(auto_now=True, verbose_name='Дата изменения') - is_published = models.BooleanField(default=True, verbose_name='Опубликован') - - def __str__(self): - return self.title - - def get_absolute_url(self): - return reverse('post', kwargs={'post_id': self.pk}) - - class Meta: - verbose_name = 'Отзыв' - verbose_name_plural = 'Отзывы' - ordering = ['time_create', 'title'] - - -class Competence(models.Model): - title = models.CharField(max_length=255, verbose_name='Программист') - content = models.TextField(blank=True, verbose_name='Компетенция') - photo = models.ImageField(upload_to="photos/%Y/%m/%d/", verbose_name='Фото') - time_create = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания') - time_update = models.DateTimeField(auto_now=True, verbose_name='Дата изменения') - is_published = models.BooleanField(default=True, verbose_name='Опубликован') - - def __str__(self): - return self.title - - def get_absolute_url(self): - return reverse('post', kwargs={'post_id': self.pk}) - - class Meta: - verbose_name = 'Компетенция' - verbose_name_plural = 'Компетенции' - ordering = ['time_create', 'title'] - - -class Solution(models.Model): - title = models.CharField(max_length=255, verbose_name='Наименование') - description = models.TextField(blank=True, verbose_name='Описание') - implementation = models.TextField(blank=True, verbose_name='Реализация') - closing = models.TextField(blank=True, verbose_name='Заключение') - time_create = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания') - time_update = models.DateTimeField(auto_now=True, verbose_name='Дата изменения') - is_published = models.BooleanField(default=True, verbose_name='Опубликован') - - def __str__(self): - return self.title - - def get_absolute_url(self): - return reverse('post', kwargs={'post_id': self.pk}) - - class Meta: - verbose_name = 'Проекты' - verbose_name_plural = 'Проекты' - ordering = ['time_create', 'title'] - - -class Home(models.Model): - title = models.CharField(max_length=255, verbose_name='Наименование') - content = models.TextField(blank=True, verbose_name='Статья') - home_image = models.ImageField(upload_to="home_image/%Y/%m/%d/", verbose_name='Фото') - time_create = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания') - time_update = models.DateTimeField(auto_now=True, verbose_name='Дата изменения') - is_published = models.BooleanField(default=True, verbose_name='Опубликован') - - def __str__(self): - return self.title - - def get_absolute_url(self): - return reverse('post', kwargs={'post_id': self.pk}) - - class Meta: - verbose_name = 'Главная страница' - verbose_name_plural = 'Главная страница' - ordering = ['time_create', 'title'] - - -class CallbackRequest(models.Model): - name = models.CharField(max_length=100, verbose_name='Имя') - phone = models.CharField(max_length=20, verbose_name='Телефон') - email = models.EmailField(blank=True, null=True, verbose_name='Электронная почта') # Сделать необязательным - question = models.TextField(blank=True, verbose_name='Ваш вопрос') # Сделать необязательным - time_create = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания') - is_processed = models.BooleanField(default=False, verbose_name='Обработано') - is_read = models.BooleanField(default=False, verbose_name='Прочитано') - notification_sent = models.BooleanField(default=False, verbose_name='Уведомление отправлено') - - def __str__(self): - return f"{self.name} - {self.phone}" - - class Meta: - verbose_name = 'Заявка на звонок' - verbose_name_plural = 'Заявки на звонок' - ordering = ['-time_create'] - - -# Сигнал для отправки уведомления при создании заявки -@receiver(post_save, sender=CallbackRequest) -def send_callback_email_notification(sender, instance, created, **kwargs): - if created and not instance.notification_sent: - # Отправляем email уведомление - success = send_callback_notification(instance) - if success: - instance.notification_sent = True - # Сохраняем без повторного вызова сигнала - sender.objects.filter(pk=instance.pk).update(notification_sent=True) - - -class PageView(models.Model): - url = models.CharField(max_length=500) - timestamp = models.DateTimeField(default=timezone.now) - ip_address = models.GenericIPAddressField() - user_agent = models.TextField(blank=True) - referer = models.CharField(max_length=500, blank=True) - - class Meta: - indexes = [ - models.Index(fields=['url', 'timestamp']), - models.Index(fields=['timestamp']), - ] - - -class Visitor(models.Model): - ip_address = models.GenericIPAddressField() - first_visit = models.DateTimeField(default=timezone.now) - last_visit = models.DateTimeField(default=timezone.now) - visit_count = models.IntegerField(default=1) - - class Meta: - indexes = [ - models.Index(fields=['ip_address']), - ] - - -@receiver([post_save, post_delete], sender=Home) -@receiver([post_save, post_delete], sender=Solution) -@receiver([post_save, post_delete], sender=Competence) -@receiver([post_save, post_delete], sender=Recall) -def clear_sitemap_cache(sender, **kwargs): - """Очищаем кэш sitemap при изменении контента""" - cache.delete('sitemap_cache') -======= from django.db import models from django.urls import reverse from django.utils import timezone @@ -334,4 +178,3 @@ class Visitor(models.Model): def clear_sitemap_cache(sender, **kwargs): """Очищаем кэш sitemap при изменении контента""" cache.delete('sitemap_cache') ->>>>>>> master diff --git a/programmer/sitemaps.py b/programmer/sitemaps.py index 16fe364..e71f587 100644 --- a/programmer/sitemaps.py +++ b/programmer/sitemaps.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from django.contrib.sitemaps import Sitemap from django.urls import reverse from .models import Home, Solution, Competence, Recall @@ -62,69 +61,4 @@ sitemaps = { 'solutions': SolutionSitemap, 'competence': CompetenceSitemap, 'recall': RecallSitemap, -======= -from django.contrib.sitemaps import Sitemap -from django.urls import reverse -from .models import Home, Solution, Competence, Recall - -class StaticViewSitemap(Sitemap): - priority = 1.0 - changefreq = 'monthly' - - def items(self): - return ['home', 'about', 'solution', 'ability', 'recall'] - - def location(self, item): - return reverse(item) - -class HomeSitemap(Sitemap): - changefreq = 'weekly' - priority = 1.0 - - def items(self): - return Home.objects.filter(is_published=True) - - def lastmod(self, obj): - return obj.time_update - - # УБИРАЕМ метод location - используем default - # Django автоматически сгенерирует правильные URL - -class SolutionSitemap(Sitemap): - changefreq = 'weekly' - priority = 0.9 - - def items(self): - return Solution.objects.filter(is_published=True) - - def lastmod(self, obj): - return obj.time_update - -class CompetenceSitemap(Sitemap): - changefreq = 'monthly' - priority = 0.8 - - def items(self): - return Competence.objects.filter(is_published=True) - - def lastmod(self, obj): - return obj.time_update - -class RecallSitemap(Sitemap): - changefreq = 'monthly' - priority = 0.7 - - def items(self): - return Recall.objects.filter(is_published=True) - - def lastmod(self, obj): - return obj.time_update - -# Упрощаем sitemaps - убираем HomeSitemap если он дублирует главную -sitemaps = { - 'static': StaticViewSitemap, - 'solutions': SolutionSitemap, - 'competence': CompetenceSitemap, - 'recall': RecallSitemap, ->>>>>>> master } \ No newline at end of file diff --git a/programmer/templates/admin/base.html b/programmer/templates/admin/base.html index 42d2eb0..c8f00f5 100644 --- a/programmer/templates/admin/base.html +++ b/programmer/templates/admin/base.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD @@ -77,84 +76,4 @@ {% bootstrap_javascript %} -======= - - - - - - {% block title %}Админ-панель - Статистика{% endblock %} - {% load django_bootstrap5 %} - {% bootstrap_css %} - - - -
-
-
-

{% block page_title %}Админ-панель{% endblock %}

-
- На сайт - Django Admin - Выйти -
-
-
-
- -
- {% bootstrap_messages %} - {% block content %} - {% endblock %} -
- - {% bootstrap_javascript %} - ->>>>>>> master \ No newline at end of file diff --git a/programmer/templates/admin/base_site.html b/programmer/templates/admin/base_site.html index 5481d79..58bd451 100644 --- a/programmer/templates/admin/base_site.html +++ b/programmer/templates/admin/base_site.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD {% extends "admin/base.html" %} {% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} @@ -24,31 +23,4 @@ 📊 Статистика заявок / 📈 Посещения / {{ block.super }} -======= -{% extends "admin/base.html" %} - -{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} - -{% block branding %} -

{{ site_header|default:_('Django administration') }}

-{% endblock %} - -{% block nav-global %} -{% endblock %} - -{% block userlinks %} - {% load programmer_tags %} - - - {% get_unread_callbacks as unread_callbacks %} - {% if unread_callbacks %} - - 🚨 {{ unread_callbacks }} новых заявок - / - {% endif %} - - 📊 Статистика заявок / - 📈 Посещения / - {{ block.super }} ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/admin/callback_stats.html b/programmer/templates/admin/callback_stats.html index 9845dd7..916c167 100644 --- a/programmer/templates/admin/callback_stats.html +++ b/programmer/templates/admin/callback_stats.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD {% extends "admin/base_site.html" %} {% block title %}Статистика заявок{% endblock %} @@ -43,50 +42,4 @@ -======= -{% extends "admin/base_site.html" %} - -{% block title %}Статистика заявок{% endblock %} - -{% block content %} -
-

📊 Статистика заявок на обратный звонок

- -
-
-

📋 Всего заявок

-

{{ stats.total }}

-
- -
-

📅 Сегодня

-

{{ stats.today }}

-
- -
-

📈 За неделю

-

{{ stats.week }}

-
- -
-

🆕 Непрочитанные

-

{{ stats.unread }}

-
- -
-

⏳ В обработке

-

{{ stats.unprocessed }}

-
-
- -
- - 📋 Перейти к списку заявок - - - 🏠 На главную админки - -
-
->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/admin/statistics.html b/programmer/templates/admin/statistics.html index f0f8643..4a1650d 100644 --- a/programmer/templates/admin/statistics.html +++ b/programmer/templates/admin/statistics.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD {% extends 'admin/base.html' %} {% load programmer_tags %} @@ -129,136 +128,4 @@ -======= -{% extends 'admin/base.html' %} -{% load programmer_tags %} - -{% block title %}Статистика посещений{% endblock %} -{% block page_title %}Статистика посещений{% endblock %} - -{% block content %} - -{% get_unread_callbacks as unread_callbacks %} -{% get_today_callbacks as today_callbacks %} -{% if unread_callbacks > 0 %} - -{% endif %} - -
-
-
-
-

📊 Просмотров сегодня

-

{{ today_views }}

-
-
-

📈 Просмотров за неделю

-

{{ weekly_views }}

-
-
-

👥 Уникальных посетителей

-

{{ unique_visitors }}

-
-
-

🕒 Всего просмотров

-

{{ total_views }}

-
- -
-

📞 Заявок сегодня

-

{{ today_callbacks }}

-
-
-

📋 Всего заявок

-

{% get_unread_callbacks %}/{{ total_callbacks }}

- (непрочитанные/всего) -
-
-
-
- - -
-
-
-
-

🔥 Популярные страницы (за неделю)

-
-
- - - - - - - - - {% for page in popular_pages %} - - - - - {% empty %} - - - - {% endfor %} - -
СтраницаПросмотров
- {{ page.url }} - {% if page.url == '/' %} - Главная - {% endif %} - {{ page.views }}
Нет данных за выбранный период
-
-
-
-
- -
-
-
-
-

📋 Последние посещения

-
-
- - - - - - - - - - {% for view in recent_views %} - - - - - - {% empty %} - - - - {% endfor %} - -
ВремяСтраницаIP-адрес
{{ view.timestamp|date:"d.m.Y H:i" }}{{ view.url }}{{ view.ip_address }}
Нет данных
-
-
-
-
->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/emails/callback_notification.html b/programmer/templates/emails/callback_notification.html index e91be02..4e7cdd8 100644 --- a/programmer/templates/emails/callback_notification.html +++ b/programmer/templates/emails/callback_notification.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD @@ -55,62 +54,4 @@ -======= - - - - - - - - -
-
-

🚨 Новая заявка на сайте

-

Требуется ваше внимание!

-
- -
-
- ⚠️ Срочно! Пользователь оставил заявку на обратный звонок. -
- -
-

📋 Информация о заявке:

-

👤 Имя: {{ callback.name }}

-

📞 Телефон: {{ callback.phone }}

- {% if callback.email %} -

📧 Email: {{ callback.email }}

- {% endif %} - {% if callback.question %} -

❓ Вопрос:
{{ callback.question }}

- {% endif %} -

🕒 Время отправки: {{ callback.time_create|date:"d.m.Y H:i" }}

-
- -
- - 📋 Перейти к заявкам в админке - -
- -

Не забудьте отметить заявку как обработанную после связи с клиентом!

-
- - -
- ->>>>>>> master \ No newline at end of file diff --git a/programmer/templates/emails/daily_summary.html b/programmer/templates/emails/daily_summary.html index 86d307d..7886975 100644 --- a/programmer/templates/emails/daily_summary.html +++ b/programmer/templates/emails/daily_summary.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD @@ -58,65 +57,4 @@ -======= - - - - - - - - -
-
-

📊 Ежедневная сводка

-

Статистика заявок за {{ yesterday|date:"d.m.Y" }}

-
- -
-
-
-

📅 Вчерашние заявки

-

{{ yesterday_callbacks }}

-
- -
-

⏳ Ожидают обработки

-

{{ unprocessed_callbacks }}

-
-
- - {% if unprocessed_callbacks > 0 %} -
- ⚠️ Внимание! У вас есть {{ unprocessed_callbacks }} необработанных заявок. -
- {% endif %} - -
- - 📋 Управление заявками - -
- -

Не забудьте обработать все pending заявки!

-
- - -
- ->>>>>>> master \ No newline at end of file diff --git a/programmer/templates/programmer/about.html b/programmer/templates/programmer/about.html index 1515dd4..696fa6d 100644 --- a/programmer/templates/programmer/about.html +++ b/programmer/templates/programmer/about.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD {% extends 'programmer/base.html' %} {% load django_bootstrap5 %} @@ -152,159 +151,4 @@ } -======= -{% extends 'programmer/base.html' %} -{% load django_bootstrap5 %} - -{% block content %} - - -
-
-

Николай Сердюк

-

Разработчик 1С

-
- -
-

🚀 Опыт работы

-

Более 10 лет успешной работы в разработке и сопровождении систем на платформе 1С

- -
-

Основные направления:

-
-
-

💻 Разработка

-
    -
  • Разработка и доработка конфигураций 1С
  • -
  • Создание внешних обработок и отчетов
  • -
  • Кастомизация под бизнес-процессы
  • -
-
-
-

🔗 Интеграция

-
    -
  • Интеграция 1С с веб-сервисами
  • -
  • Связь с сайтами и мобильными приложениями
  • -
  • API и веб-сервисы
  • -
-
-
-

⚡ Оптимизация

-
    -
  • Оптимизация бизнес-процессов
  • -
  • Ускорение работы баз данных
  • -
  • Автоматизация рутинных операций
  • -
-
-
-
-
- -
-

🛠 Технологии и навыки

-
-
-

🎯 1С Разработка

-
    -
  • 1С:Предприятие 8.3
  • -
  • Управление торговлей
  • -
  • Бухгалтерия предприятия
  • -
  • Зарплата и управление персоналом
  • -
  • Внешние обработки и отчеты
  • -
-
-
-

🔧 Дополнительные технологии

-
    -
  • SQL и оптимизация запросов
  • -
  • Веб-сервисы и API
  • -
  • XML, JSON, REST
  • -
  • Системное администрирование
  • -
-
-
-
- -
-

📈 Проекты и достижения

-

Успешно реализовал более 50 проектов различной сложности

- -
-
-

🏆 Ключевые проекты

-
    -
  • Автоматизация учетных систем для предприятий
  • -
  • Интеграция 1С с сайтами и мобильными приложениями
  • -
  • Разработка кастомизированных отчетов и дашбордов
  • -
  • Оптимизация производительности баз данных
  • -
-
-
-
- -
-

📞 Контакты

-
-
-
-

📧 Электронная почта

-

{{ CONTACT_EMAIL }}

-
-
-

📱 Телефон

-

{{ CONTACT_PHONE }}

-
-
-

💬 Telegram

-

@odinesina_prog

-
-
-
-
- -
- -
-
- - - ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/programmer/base.html b/programmer/templates/programmer/base.html index 933f594..ff10cda 100644 --- a/programmer/templates/programmer/base.html +++ b/programmer/templates/programmer/base.html @@ -1,559 +1,3 @@ -<<<<<<< HEAD -{% load static %} -{% load programmer_tags %} -{% load django_bootstrap5 %} - - - - {{title}} - Программист 1С - - - - - - - - - - - - - - - - - - - - - - - {% bootstrap_css %} - - - - - - - - - - - - {% block extra_css %} - - {% endblock %} - - - - - - - - - - - - - - - {% block mainmenu %} -
-
- -
-
- - -
-
-
-

Меню

- -
- - - -
- - - Telegram - - -
- - -
-
-
- {% endblock mainmenu %} - - -
-
-
- - {% block breadcrumbs %} - - {% endblock %} - - - {% bootstrap_messages %} - - -
- {% block content %} - {% endblock %} -
-
-
-
- - - - - {% bootstrap_javascript %} - - - - {% block extra_js %} - - {% endblock %} - -======= {% load static %} {% load programmer_tags %} {% load django_bootstrap5 %} @@ -1131,5 +575,4 @@ } ->>>>>>> master \ No newline at end of file diff --git a/programmer/templates/programmer/callback.html b/programmer/templates/programmer/callback.html index 7528544..9106615 100644 --- a/programmer/templates/programmer/callback.html +++ b/programmer/templates/programmer/callback.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD {% extends 'programmer/base.html' %} {% load django_bootstrap5 %} @@ -6,13 +5,4 @@ -======= -{% extends 'programmer/base.html' %} -{% load django_bootstrap5 %} - -{% block content %} - - - ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/programmer/competence.html b/programmer/templates/programmer/competence.html index 19e565f..2c261b5 100644 --- a/programmer/templates/programmer/competence.html +++ b/programmer/templates/programmer/competence.html @@ -1,76 +1,3 @@ -<<<<<<< HEAD -{% extends 'programmer/base.html' %} -{% load django_bootstrap5 %} -{% load static %} - -{% block extra_css %} - -{% endblock %} - -{% block content %} - - -
- {% for p in posts %} -
-
- {% if p.photo %} -
-
- {{ p.title }} -
- 🔍 - Нажмите для увеличения -
-
-
- {% endif %} - -
-

{{ p.title }}

-
- {{ p.content|linebreaks }} -
-
-
-
- {% endfor %} -
- -{% if not posts %} -
-

📚 Информация о компетенциях

-

Раздел находится в разработке

-
- Посмотреть проекты - Обо мне -
-
-{% endif %} - - - -{% endblock %} - -{% block extra_js %} - -======= {% extends 'programmer/base.html' %} {% load django_bootstrap5 %} {% load static %} @@ -142,5 +69,4 @@ {% block extra_js %} ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/programmer/humans.txt b/programmer/templates/programmer/humans.txt index c32412e..7a8f4bc 100644 --- a/programmer/templates/programmer/humans.txt +++ b/programmer/templates/programmer/humans.txt @@ -1,4 +1,3 @@ -<<<<<<< HEAD /* TEAM */ Developer: Николай Сердюк Site: https://nikdizell.ru @@ -11,18 +10,4 @@ Bootstrap /* SITE */ Last update: 2025 Language: Russian -======= -/* TEAM */ -Developer: Николай Сердюк -Site: https://nikdizell.ru -Email: {{ CONTACT_EMAIL }} - -/* THANKS */ -Django Framework -Bootstrap - -/* SITE */ -Last update: 2025 -Language: Russian ->>>>>>> master Doctype: HTML5 \ No newline at end of file diff --git a/programmer/templates/programmer/index.html b/programmer/templates/programmer/index.html index 8539a39..ca59bd6 100644 --- a/programmer/templates/programmer/index.html +++ b/programmer/templates/programmer/index.html @@ -1,4 +1,3 @@ -<<<<<<< HEAD {% extends 'programmer/base.html' %} {% load django_bootstrap5 %} @@ -101,108 +100,4 @@ document.addEventListener('keydown', function(event) { } }); -======= -{% extends 'programmer/base.html' %} -{% load django_bootstrap5 %} - -{% block content %} -
-

🚀 Добро пожаловать!

-

Я профессиональный программист 1С с опытом создания эффективных бизнес-решений

-
- -
- {% autoescape off %} - {% for p in posts %} -
-
-

{{p.title}}

-
-
- {{p.content}} -
-
- -
-
- {% endfor %} - {% endautoescape %} -
- - - - -{% if not posts %} -
-

🚀 Контент скоро появится

-

Мы готовим для вас интересные материалы и кейсы

-
- -
-
-{% endif %} - - ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/programmer/recall.html b/programmer/templates/programmer/recall.html index 83a4b8f..faca463 100644 --- a/programmer/templates/programmer/recall.html +++ b/programmer/templates/programmer/recall.html @@ -1,153 +1,3 @@ -<<<<<<< HEAD -{% extends 'programmer/base.html' %} -{% load django_bootstrap5 %} -{% load static %} - -{% block extra_css %} - -{% endblock %} - -{% block content %} - - -
- {% for p in posts %} -
-
-
-
-

{{ p.title }}

- {% if p.time_create %} - - - - {% endif %} -
-
- -
- {% if p.scan %} -
-
- Отзыв от {{ p.title }} -
- 🔍 - Нажмите для увеличения -
-
-
- {% endif %} - -
- {{ p.content|linebreaks }} -
-
-
-
- {% endfor %} -
- -{% if not posts %} -
-

💬 Отзывы клиентов

-

Здесь будут отображаться отзывы от довольных клиентов

-
- Посмотреть проекты - Связаться со мной -
-
-{% endif %} - - - - - -======= {% extends 'programmer/base.html' %} {% load django_bootstrap5 %} {% load static %} @@ -321,5 +171,4 @@ function adjustModalImageSize() { {% block extra_js %} ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templates/programmer/robots.txt b/programmer/templates/programmer/robots.txt index 437205e..32d69b7 100644 --- a/programmer/templates/programmer/robots.txt +++ b/programmer/templates/programmer/robots.txt @@ -1,22 +1,3 @@ -<<<<<<< HEAD -User-agent: * -Allow: / - -# Основной сайт -Sitemap: {{ request.scheme }}://{{ request.get_host }}/sitemap.xml - -# Запрещаем служебные разделы -Disallow: /admin/ -Disallow: /static/admin/ -Disallow: /callback/ -Disallow: /api/ - -# Разрешаем индексацию статических файлов -Allow: /static/ -Allow: /media/ - -# Указываем главное зеркало -======= User-agent: * Allow: / @@ -35,5 +16,4 @@ Allow: /static/ Allow: /media/ # Указываем главное зеркало ->>>>>>> master Host: {{ request.scheme }}://{{ request.get_host }} \ No newline at end of file diff --git a/programmer/templates/programmer/sitemap.xml b/programmer/templates/programmer/sitemap.xml index fe18a95..62e1b06 100644 --- a/programmer/templates/programmer/sitemap.xml +++ b/programmer/templates/programmer/sitemap.xml @@ -1,4 +1,3 @@ -<<<<<<< HEAD @@ -10,17 +9,4 @@ {% if url.priority %}{{ url.priority }}{% endif %} {% endfor %} -======= - - -{% for url in urlset %} - - {{ url.location }} - {% if url.lastmod %}{{ url.lastmod|date:"Y-m-d" }}{% endif %} - {% if url.changefreq %}{{ url.changefreq }}{% endif %} - {% if url.priority %}{{ url.priority }}{% endif %} - -{% endfor %} ->>>>>>> master \ No newline at end of file diff --git a/programmer/templates/programmer/solution.html b/programmer/templates/programmer/solution.html index e184af4..babc513 100644 --- a/programmer/templates/programmer/solution.html +++ b/programmer/templates/programmer/solution.html @@ -1,74 +1,3 @@ -<<<<<<< HEAD -{% extends 'programmer/base.html' %} -{% load django_bootstrap5 %} -{% load static %} - -{% block extra_css %} - -{% endblock %} - -{% block content %} -

{{title}}

- -
- {% autoescape off %} - {% for p in posts %} -
  • -
    -

    {{p.title}}

    - -
    -
    -
    - 📋 Описание задачи - -
    -
    - {{p.description}} -
    -
    - -
    -
    - 🔧 Описание решения - -
    -
    - {{p.implementation}} -
    -
    - -
    -
    - ✅ Результат - -
    -
    - {{p.closing}} -
    -
    -
    - -
    -

    Опубликовано: {{p.time_create|date:"d.m.Y"}}

    -
    -
    -
  • - {% endfor %} - {% endautoescape %} -
    - -{% if not posts %} -
    -

    Примеры решений скоро появятся

    -

    Мы готовим для вас интересные кейсы и решения

    -
    -{% endif %} - - - - -======= {% extends 'programmer/base.html' %} {% load django_bootstrap5 %} {% load static %} @@ -164,5 +93,4 @@ ->>>>>>> master {% endblock %} \ No newline at end of file diff --git a/programmer/templatetags/programmer_tags.py b/programmer/templatetags/programmer_tags.py index 67afdc1..b7b1498 100644 --- a/programmer/templatetags/programmer_tags.py +++ b/programmer/templatetags/programmer_tags.py @@ -1,19 +1,3 @@ -<<<<<<< HEAD -from django import template -from programmer.models import * - - -register = template.Library() - -@register.simple_tag(name='competence') -def get_competence(): - return Competence.objects.all() - - -@register.simple_tag(name='recall') -def get_recall(): - return Recall.objects.all() -======= from django import template from ..models import CallbackRequest @@ -28,4 +12,3 @@ def get_today_callbacks(): from django.utils import timezone today = timezone.now().date() return CallbackRequest.objects.filter(time_create__date=today).count() ->>>>>>> master diff --git a/programmer/tests.py b/programmer/tests.py index 0e7885b..7ce503c 100644 --- a/programmer/tests.py +++ b/programmer/tests.py @@ -1,9 +1,3 @@ -<<<<<<< HEAD from django.test import TestCase # Create your tests here. -======= -from django.test import TestCase - -# Create your tests here. ->>>>>>> master diff --git a/programmer/urls.py b/programmer/urls.py index 0547193..ed69c18 100644 --- a/programmer/urls.py +++ b/programmer/urls.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from django.contrib import admin from django.urls import path, include from django.conf import settings @@ -25,32 +24,4 @@ urlpatterns = [ if settings.DEBUG: -======= -from django.contrib import admin -from django.urls import path, include -from django.conf import settings -from django.conf.urls.static import static -from .views import * -from django.contrib.sitemaps.views import sitemap -from .sitemaps import sitemaps - - -urlpatterns = [ - path('', index, name='home'), - path('about/', about, name='about'), - path('solutions/', solution, name='solution'), - path('competence/', ability, name='ability'), - path('recall/', recall, name='recall'), - path('post//', show_post, name='post'), - path('callback/', callback_request, name='callback'), - path('admin/statistics/', statistics_view, name='statistics'), - # Sitemap - path('sitemap.xml', sitemap, {'sitemaps': sitemaps}, - name='django.contrib.sitemaps.views.sitemap'), - path('robots.txt', robots_txt, name='robots'), -] - - -if settings.DEBUG: ->>>>>>> master urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/programmer/views.py b/programmer/views.py index 7601fe6..999b213 100644 --- a/programmer/views.py +++ b/programmer/views.py @@ -1,258 +1,3 @@ -<<<<<<< HEAD -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': "Главная страница", - 'meta_description': "Профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция и оптимизация систем 1С. Закажите консультацию.", - 'meta_keywords': "программист 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С", - 'meta_description': "Николай Сердюк - профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция, оптимизация бизнес-процессов.", - 'meta_keywords': "программист 1С Николай Сердюк, опыт работы 1С, компетенции 1С, проекты 1С" - } - 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, - 'title': "Проекты" - } - 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': "Компетенции" - } - 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': "Отзывы" - } - 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('

    Страница не найдена

    ') - - -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') -======= from django.http import HttpResponse, HttpResponseNotFound from .models import * from django.shortcuts import render, redirect @@ -512,4 +257,3 @@ def statistics_view(request): @require_GET def robots_txt(request): return render(request, 'robots.txt', content_type='text/plain') ->>>>>>> master