From c1cc6be0cdebfe945d6629d0f8172b699893fc21 Mon Sep 17 00:00:00 2001 From: Zareian Date: Thu, 8 Oct 2026 12:41:06 +0330 Subject: [PATCH] User activity file includes failed logins matched by phone Co-Authored-By: Claude Sonnet 5.5 --- accounts/activity.py | 5 ++++- accounts/tests_user_activity.py | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/accounts/activity.py b/accounts/activity.py index af58731..33e9b23 100644 --- a/accounts/activity.py +++ b/accounts/activity.py @@ -5,6 +5,7 @@ ناهماهنگ نمی‌شود. تصمیمِ ادغام‌نکردنِ این‌ها در یک جدول: ستون‌هایشان فرق دارد. آزموده نشده: کاربری با ده‌ها هزار ردیف (همه‌ی ردیف‌ها در حافظه می‌آیند). """ +from django.db.models import Q from django.utils import timezone from payment.models import Order @@ -19,7 +20,9 @@ COLUMNS = ['زمان', 'نوع', 'شرح', 'مبلغ', 'آی‌پی'] def user_activity(user: User) -> list[dict]: rows = [{'at': user.created_at, 'kind': 'ثبت‌نام', 'detail': '', 'amount': '', 'ip': ''}] - for e in LoginEvent.objects.filter(user_id=user.id): + # ورودِ ناموفق هنوز user_id ندارد (کاربر معلوم نیست)، پس با شماره هم می‌گیریم. + by_user = Q(user_id=user.id) | (Q(phone=user.phone) if user.phone else Q(pk__in=[])) + for e in LoginEvent.objects.filter(by_user): rows.append({'at': e.created_at, 'kind': _EVENT_FA.get(e.event, e.event), 'detail': e.user_agent[:80], 'amount': '', 'ip': e.ip or ''}) orders = list(Order.objects.filter(user_id=user.id)) diff --git a/accounts/tests_user_activity.py b/accounts/tests_user_activity.py index 8da46d6..cb5689f 100644 --- a/accounts/tests_user_activity.py +++ b/accounts/tests_user_activity.py @@ -37,5 +37,10 @@ class UserActivityTests(TestCase): self.client.force_login(s) self.assertEqual(self.client.get(f'/admin/accounts/user/{self.user.id}/activity/').status_code, 403) + def test_failed_login_by_phone_is_included(self): + LoginEvent.objects.create(event='login_failed', phone=self.user.phone, ip='198.51.100.4') + r = self.client.get(f'/admin/accounts/user/{self.user.id}/activity/') + self.assertIn('ورود ناموفق', r.content.decode()) + def test_unknown_user_is_404(self): self.assertEqual(self.client.get('/admin/accounts/user/999999/activity/').status_code, 404)