delete_users: only project models; Django admin history (LogEntry.user_id is staff) was being counted
Account deletion also keeps the status log of the payment records it keeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,11 +34,25 @@ USER_COLUMNS = ('user_id', 'referred_user_id')
|
|||||||
|
|
||||||
|
|
||||||
def user_scoped_models():
|
def user_scoped_models():
|
||||||
"""[(model, column)] برای هر مدلی که به کاربر ارجاع میدهد، جز خودِ User."""
|
"""
|
||||||
|
[(model, column)] برای هر مدلِ خودِ پروژه که به کاربرِ اپ ارجاع میدهد، جز خودِ User.
|
||||||
|
|
||||||
|
فقط اپهایی که داخلِ پوشهی پروژهاند. `admin.LogEntry` هم ستونِ user_id دارد ولی آن
|
||||||
|
کارمندِ ادمینِ جنگوست، نه کاربرِ اپ؛ بارِ اول که این دستور روی سرور گزارش گرفت، همان را
|
||||||
|
هم شمرده بود و اگر اجرا میشد تاریخچهی ادمینِ شمارهی ۱ پاک میشد.
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
base = Path(settings.BASE_DIR).resolve()
|
||||||
found = []
|
found = []
|
||||||
for model in apps.get_models():
|
for model in apps.get_models():
|
||||||
if model is User:
|
if model is User:
|
||||||
continue
|
continue
|
||||||
|
app_path = Path(model._meta.app_config.path).resolve()
|
||||||
|
if base not in app_path.parents or 'site-packages' in app_path.parts:
|
||||||
|
continue
|
||||||
names = {f.attname for f in model._meta.concrete_fields}
|
names = {f.attname for f in model._meta.concrete_fields}
|
||||||
found += [(model, column) for column in USER_COLUMNS if column in names]
|
found += [(model, column) for column in USER_COLUMNS if column in names]
|
||||||
return found
|
return found
|
||||||
|
|||||||
@@ -63,3 +63,15 @@ class DeleteUsersTests(TestCase):
|
|||||||
self.run_command('--ids', str(self.doomed.pk), str(self.kept.pk), '--yes', '--skip-paid')
|
self.run_command('--ids', str(self.doomed.pk), str(self.kept.pk), '--yes', '--skip-paid')
|
||||||
self.assertTrue(User.objects.filter(pk=self.doomed.pk).exists())
|
self.assertTrue(User.objects.filter(pk=self.doomed.pk).exists())
|
||||||
self.assertFalse(User.objects.filter(pk=self.kept.pk).exists())
|
self.assertFalse(User.objects.filter(pk=self.kept.pk).exists())
|
||||||
|
|
||||||
|
def test_django_admin_history_is_never_touched(self):
|
||||||
|
from django.contrib.admin.models import LogEntry
|
||||||
|
from django.contrib.auth.models import User as StaffUser
|
||||||
|
|
||||||
|
from accounts.management.commands.delete_users import user_scoped_models
|
||||||
|
|
||||||
|
self.assertNotIn(LogEntry, [model for model, _ in user_scoped_models()])
|
||||||
|
staff = StaffUser.objects.create(id=self.doomed.pk, username='staff')
|
||||||
|
LogEntry.objects.create(user=staff, action_flag=1, object_repr='x')
|
||||||
|
self.run_command('--ids', str(self.doomed.pk), '--yes')
|
||||||
|
self.assertEqual(LogEntry.objects.count(), 1)
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ def _upgradable_guest(request, phone: str):
|
|||||||
|
|
||||||
DELETE_CONFIRM_WORD = 'حذف'
|
DELETE_CONFIRM_WORD = 'حذف'
|
||||||
# سوابقِ پرداخت سندِ مالیاند و با حذفِ حساب نمیروند (تراکنشها با سفارش میمانند).
|
# سوابقِ پرداخت سندِ مالیاند و با حذفِ حساب نمیروند (تراکنشها با سفارش میمانند).
|
||||||
KEPT_ON_ACCOUNT_DELETE = ('payment.Order',)
|
KEPT_ON_ACCOUNT_DELETE = ('payment.Order', 'statuslog.StatusChangeLog')
|
||||||
|
|
||||||
|
|
||||||
class DeleteAccountView(APIView):
|
class DeleteAccountView(APIView):
|
||||||
|
|||||||
Reference in New Issue
Block a user