from django.contrib import admin from django.contrib.auth import get_user_model from django.test import TestCase from django.urls import reverse from apps.billing.models import PointsLedger from apps.users.models import ApiKey, UserWallet class AdminSmokeTests(TestCase): def test_custom_user_is_registered_in_admin(self): self.assertIn(get_user_model(), admin.site._registry) def test_superuser_can_login_to_admin(self): user_model = get_user_model() user_model.objects.create_superuser( username="admin", email="admin@example.com", password="test-password", ) logged_in = self.client.login(username="admin", password="test-password") self.assertTrue(logged_in) response = self.client.get(reverse("admin:index")) self.assertEqual(response.status_code, 200) class UserAdminOperationTests(TestCase): def setUp(self): user_model = get_user_model() self.admin_user = user_model.objects.create_superuser( username="ops-admin", email="ops-admin@example.com", password="test-password", ) self.user = user_model.objects.create_user( username="client-user", email="client-user@example.com", password="test-password", ) self.wallet = UserWallet.objects.create(user=self.user, points_balance=100) self.client.force_login(self.admin_user) def test_wallet_adjust_admin_view_calls_billing_service_and_writes_ledger(self): url = reverse("admin:users_userwallet_adjust_points", args=(self.wallet.pk,)) get_response = self.client.get(url) self.assertEqual(get_response.status_code, 200) self.assertContains(get_response, "手工调整点数") self.assertContains(get_response, "当前余额") response = self.client.post( url, { "points_delta": "30", "reason": "运营补偿", }, ) self.assertEqual(response.status_code, 302) self.wallet.refresh_from_db() self.assertEqual(self.wallet.points_balance, 130) ledger = PointsLedger.objects.get( user=self.user, change_type=PointsLedger.ChangeType.ADJUST, ) self.assertEqual(ledger.points_delta, 30) self.assertEqual(ledger.balance_after, 130) self.assertIn("运营补偿", ledger.reason) self.assertIn("operator=ops-admin#", ledger.reason) def test_wallet_adjust_admin_requires_reason_and_keeps_balance_unchanged(self): url = reverse("admin:users_userwallet_adjust_points", args=(self.wallet.pk,)) response = self.client.post( url, { "points_delta": "30", "reason": "", }, ) self.assertEqual(response.status_code, 200) self.wallet.refresh_from_db() self.assertEqual(self.wallet.points_balance, 100) self.assertFalse( PointsLedger.objects.filter( user=self.user, change_type=PointsLedger.ChangeType.ADJUST, ).exists() ) def test_wallet_admin_change_form_does_not_directly_edit_balance(self): url = reverse("admin:users_userwallet_change", args=(self.wallet.pk,)) response = self.client.post(url, {"points_balance": "999"}, follow=True) self.assertEqual(response.status_code, 200) self.wallet.refresh_from_db() self.assertEqual(self.wallet.points_balance, 100) self.assertFalse( PointsLedger.objects.filter( user=self.user, change_type=PointsLedger.ChangeType.ADJUST, ).exists() ) def test_api_key_admin_hides_plaintext_and_full_hash(self): api_key, raw_key = ApiKey.create_for_user(self.user, name="desktop") url = reverse("admin:users_apikey_change", args=(api_key.pk,)) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, api_key.key_prefix) self.assertNotContains(response, raw_key) self.assertNotContains(response, api_key.key_hash)