From 6d387ad4e2b611f944ff9aecc324870f960b6616 Mon Sep 17 00:00:00 2001 From: Viner Abubakirov Date: Sun, 4 Jan 2026 02:07:08 +0500 Subject: [PATCH 1/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BB=D0=BE=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9=20=D1=81=D0=B0=D0=B9=D1=82=D0=B0=20(=D1=8D?= =?UTF-8?q?=D0=BA=D1=81=D0=BF=D0=B5=D1=80=D0=B8=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- music_storage/logger/__init__.py | 0 music_storage/logger/admin.py | 3 ++ music_storage/logger/apps.py | 5 +++ music_storage/logger/middleware.py | 29 +++++++++++++++ .../logger/migrations/0001_initial.py | 37 +++++++++++++++++++ music_storage/logger/migrations/__init__.py | 0 music_storage/logger/models.py | 19 ++++++++++ music_storage/logger/tests.py | 3 ++ music_storage/logger/views.py | 3 ++ music_storage/music_storage/settings.py | 2 + 10 files changed, 101 insertions(+) create mode 100644 music_storage/logger/__init__.py create mode 100644 music_storage/logger/admin.py create mode 100644 music_storage/logger/apps.py create mode 100644 music_storage/logger/middleware.py create mode 100644 music_storage/logger/migrations/0001_initial.py create mode 100644 music_storage/logger/migrations/__init__.py create mode 100644 music_storage/logger/models.py create mode 100644 music_storage/logger/tests.py create mode 100644 music_storage/logger/views.py diff --git a/music_storage/logger/__init__.py b/music_storage/logger/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/music_storage/logger/admin.py b/music_storage/logger/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/music_storage/logger/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/music_storage/logger/apps.py b/music_storage/logger/apps.py new file mode 100644 index 0000000..2c1a7d7 --- /dev/null +++ b/music_storage/logger/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class LoggerConfig(AppConfig): + name = 'logger' diff --git a/music_storage/logger/middleware.py b/music_storage/logger/middleware.py new file mode 100644 index 0000000..2fef1cd --- /dev/null +++ b/music_storage/logger/middleware.py @@ -0,0 +1,29 @@ +from .models import AccessLog + + +class AccessLogMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + response = self.get_response(request) + + user = getattr(request, "user", None) + username = user.username if user and user.is_authenticated else "Anonymous" + method = request.method + path = request.get_full_path() + ip_address = self.get_client_ip(request) + + AccessLog.objects.create( + username=username, method=method, path=path, ip_address=ip_address + ) + + return response + + 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") + return ip diff --git a/music_storage/logger/migrations/0001_initial.py b/music_storage/logger/migrations/0001_initial.py new file mode 100644 index 0000000..e2c4af6 --- /dev/null +++ b/music_storage/logger/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 6.0 on 2026-01-03 20:40 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='AccessLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('username', models.CharField(max_length=150)), + ('method', models.CharField(max_length=10)), + ('path', models.CharField(max_length=2048)), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('ip_address', models.GenericIPAddressField(blank=True, null=True)), + ('created_by', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)), + ('updated_by', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Access Log', + 'verbose_name_plural': 'Access Logs', + 'ordering': ['-timestamp'], + }, + ), + ] diff --git a/music_storage/logger/migrations/__init__.py b/music_storage/logger/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/music_storage/logger/models.py b/music_storage/logger/models.py new file mode 100644 index 0000000..a80a343 --- /dev/null +++ b/music_storage/logger/models.py @@ -0,0 +1,19 @@ +from django.db import models +from core.models import BaseModel + + +class AccessLog(BaseModel): + """Model to store access logs for user requests.""" + class Meta: + verbose_name = "Access Log" + verbose_name_plural = "Access Logs" + ordering = ['-timestamp'] + + username = models.CharField(max_length=150) + method = models.CharField(max_length=10) + path = models.CharField(max_length=2048) + timestamp = models.DateTimeField(auto_now_add=True) + ip_address = models.GenericIPAddressField(null=True, blank=True) + + def __str__(self): + return f'[{self.timestamp}] {self.username} {self.method} {self.path}' diff --git a/music_storage/logger/tests.py b/music_storage/logger/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/music_storage/logger/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/music_storage/logger/views.py b/music_storage/logger/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/music_storage/logger/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/music_storage/music_storage/settings.py b/music_storage/music_storage/settings.py index 8454034..7311124 100644 --- a/music_storage/music_storage/settings.py +++ b/music_storage/music_storage/settings.py @@ -49,6 +49,7 @@ INSTALLED_APPS = [ # Custom apps 'core', 'music', + 'logger', ] MIDDLEWARE = [ @@ -65,6 +66,7 @@ MIDDLEWARE = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', # Custom middlewares "core.middleware.current_request.CurrentRequestMiddleware", + "logger.middleware.AccessLogMiddleware", ] ROOT_URLCONF = 'music_storage.urls' -- 2.49.1 From 2d3878c8ba8c5f103d069d2ddd08fbc8de4be62c Mon Sep 17 00:00:00 2001 From: Viner Abubakirov Date: Sun, 4 Jan 2026 02:17:56 +0500 Subject: [PATCH 2/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=B0=D0=B4=D0=BC=D0=BD=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- music_storage/logger/admin.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/music_storage/logger/admin.py b/music_storage/logger/admin.py index 8c38f3f..2e130a2 100644 --- a/music_storage/logger/admin.py +++ b/music_storage/logger/admin.py @@ -1,3 +1,21 @@ from django.contrib import admin -# Register your models here. +from .models import AccessLog + + +@admin.register(AccessLog) +class AccessLogAdmin(admin.ModelAdmin): + list_display = ('timestamp', 'username', 'method', 'path', 'ip_address') + list_filter = ('method', 'timestamp') + search_fields = ('username', 'path', 'ip_address') + readonly_fields = ('timestamp', 'username', 'method', 'path', 'ip_address') + ordering = ('-timestamp',) + + def has_add_permission(self, request): + return False + + def has_change_permission(self, request, obj=None): + return False + + def has_delete_permission(self, request, obj=None): + return False -- 2.49.1 From 6c75b1ee7f7b18d2956df0d0440e17f412a92f0f Mon Sep 17 00:00:00 2001 From: Viner Abubakirov Date: Sun, 4 Jan 2026 12:11:42 +0500 Subject: [PATCH 3/4] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20get=5Fcurrent=5Fuser()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- music_storage/core/middleware/current_request.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/music_storage/core/middleware/current_request.py b/music_storage/core/middleware/current_request.py index cccf745..9c4c993 100644 --- a/music_storage/core/middleware/current_request.py +++ b/music_storage/core/middleware/current_request.py @@ -1,5 +1,6 @@ import threading from django.utils.deprecation import MiddlewareMixin +from django.contrib.auth.models import AnonymousUser _thread_local = threading.local() @@ -14,7 +15,9 @@ def get_current_user(): """Retrieve the user from the current request.""" request = get_current_request() if request: - return getattr(request, "user", None) + user = getattr(request, "user", None) + if not isinstance(user, AnonymousUser): + return user return None -- 2.49.1 From 87b9eeb69c3233378f1bd1e4bb06492258046a4a Mon Sep 17 00:00:00 2001 From: Viner Abubakirov Date: Sun, 4 Jan 2026 12:12:13 +0500 Subject: [PATCH 4/4] =?UTF-8?q?=D0=9D=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B4=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20ALL?= =?UTF-8?q?OWED=5FHOSTS=20=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=B5=D0=B1=D0=B0?= =?UTF-8?q?=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- music_storage/music_storage/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/music_storage/music_storage/settings.py b/music_storage/music_storage/settings.py index 7311124..7518830 100644 --- a/music_storage/music_storage/settings.py +++ b/music_storage/music_storage/settings.py @@ -27,7 +27,7 @@ SECRET_KEY = os.getenv("SECRET_KEY", "") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = os.getenv("DJANGO_DEBUG", "False") == "True" -ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",") +ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",") if not DEBUG else ["*"] if not DEBUG: USE_X_FORWARDED_HOST = True -- 2.49.1