From 23d334c5961a7a5e20b3ed9ab4dd3e3558f1f69b Mon Sep 17 00:00:00 2001 From: badbl0cks <4161747+badbl0cks@users.noreply.github.com> Date: Wed, 26 Mar 2025 14:25:09 -0700 Subject: [PATCH] Add tests for accounts, and fix allowing user to delete friend code with active trade offers and in-game-name not being set on signup --- accounts/forms.py | 7 +- accounts/models.py | 7 +- accounts/tests.py | 636 ++++++++++++++++++++++++++++++++++++- accounts/views.py | 10 +- django_project/settings.py | 2 +- trades/models.py | 6 + 6 files changed, 658 insertions(+), 10 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index af40a45..17f00ac 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -74,12 +74,13 @@ class CustomUserCreationForm(SignupForm): def save(self, request): # First, complete the normal signup process. user = super(CustomUserCreationForm, self).save(request) - # Create the associated FriendCode record. - friend_code_pk = FriendCode.objects.create( + # Create the associated FriendCode record, now including in_game_name. + friend_code_instance = FriendCode.objects.create( friend_code=self.cleaned_data["friend_code"], + in_game_name=self.cleaned_data["in_game_name"], user=user ) - user.default_friend_code = friend_code_pk + user.default_friend_code = friend_code_instance user.save() return user diff --git a/accounts/models.py b/accounts/models.py index 2fbb250..9efd024 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -23,11 +23,14 @@ class CustomUser(AbstractUser): def remove_default_friend_code(self, friend_code): """ If the given friend code is the current default, - assign another of the user's friend codes (if any) as default. + assign another of the user's friend codes as default. + Raises ValidationError if it's the only friend code. """ if self.default_friend_code == friend_code: other_codes = self.friend_codes.exclude(pk=friend_code.pk) - self.default_friend_code = other_codes.first() if other_codes.exists() else None + if not other_codes.exists(): + raise ValidationError("A user must always have a default friend code.") + self.default_friend_code = other_codes.first() self.save(update_fields=["default_friend_code"]) class FriendCode(models.Model): diff --git a/accounts/tests.py b/accounts/tests.py index 7ce503c..0233194 100644 --- a/accounts/tests.py +++ b/accounts/tests.py @@ -1,3 +1,637 @@ -from django.test import TestCase +import hashlib +from unittest.mock import patch, MagicMock +import requests + +from django.contrib.auth import get_user_model +from django.test import TestCase, RequestFactory +from django.urls import reverse +from django.core.exceptions import ValidationError +from django.contrib.sessions.middleware import SessionMiddleware + +from accounts.models import FriendCode +from accounts.forms import FriendCodeForm, CustomUserCreationForm, UserSettingsForm +from accounts.templatetags import gravatar +from trades.models import TradeOffer # Create your tests here. + +# ----------------------------- +# Model Tests +# ----------------------------- +class CustomUserModelTests(TestCase): + def setUp(self): + self.user = get_user_model().objects.create_user( + username="testuser", + email="test@example.com", + password="password123" + ) + def test_set_default_friend_code(self): + """User can manually set a friend code as their default.""" + fc1 = FriendCode.objects.create( + friend_code="1234-5678-9012-3456", + user=self.user, + in_game_name="GameOne" + ) + fc2 = FriendCode.objects.create( + friend_code="2345-6789-0123-4567", + user=self.user, + in_game_name="GameTwo" + ) + # Manually set fc2 as default. + self.user.set_default_friend_code(fc2) + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, fc2) + + def test_set_default_friend_code_invalid(self): + """ + Attempting to set a friend code that does not belong to the user should raise an exception. + """ + other_user = get_user_model().objects.create_user( + username="otheruser", + email="other@example.com", + password="password456" + ) + fc_other = FriendCode.objects.create( + friend_code="3456-7890-1234-5678", + user=other_user, + in_game_name="OtherGame" + ) + with self.assertRaises(ValidationError): + self.user.set_default_friend_code(fc_other) + + def test_remove_default_friend_code_with_multiple_codes(self): + """ + When removing the default friend code and other friend codes exist, + the default should be reassigned to another friend code. + """ + fc1 = FriendCode.objects.create( + friend_code="1234-5678-9012-3456", + user=self.user, + in_game_name="GameOne" + ) + fc2 = FriendCode.objects.create( + friend_code="2345-6789-0123-4567", + user=self.user, + in_game_name="GameTwo" + ) + # Set fc2 as default. + self.user.set_default_friend_code(fc2) + # Removing fc2 should reassign the default to fc1. + self.user.remove_default_friend_code(fc2) + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, fc1) + + def test_removing_only_friend_code_raises(self): + """ + A user must always have a default friend code. + Attempting to remove the only friend code (and thus the default) + should be prohibited. + """ + fc = FriendCode.objects.create( + friend_code="1234-5678-9012-3456", + user=self.user, + in_game_name="OnlyGame" + ) + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, fc) + with self.assertRaises(ValidationError): + self.user.remove_default_friend_code(fc) + + def test_remove_non_default_friend_code_does_nothing(self): + """ + When attempting to remove a friend code that isn't the default, + the current default should remain unchanged. + """ + fc1 = FriendCode.objects.create( + friend_code="1234-5678-9012-3456", + user=self.user, + in_game_name="GameOne" + ) + fc2 = FriendCode.objects.create( + friend_code="2345-6789-0123-4567", + user=self.user, + in_game_name="GameTwo" + ) + # By default, fc1 is the default friend code. + self.assertEqual(self.user.default_friend_code, fc1) + try: + self.user.remove_default_friend_code(fc2) + except Exception as e: + self.fail("remove_default_friend_code raised an exception when removing a non-default code.") + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, fc1) + + +# ----------------------------- +# FriendCode Model Tests +# ----------------------------- +class FriendCodeModelTests(TestCase): + def setUp(self): + self.user = get_user_model().objects.create_user( + username="testuser2", + email="test2@example.com", + password="password123" + ) + + def test_default_set_on_creation(self): + """ + When creating a FriendCode for a user with no default, + the new friend code is automatically set as the default. + """ + fc = FriendCode.objects.create( + friend_code="1234-5678-9012-3456", + user=self.user, + in_game_name="GameDefault" + ) + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, fc) + + def test_adding_additional_friend_code_preserves_default(self): + """ + When additional friend codes are added to a user who already has a default, + the initial friend code remains the default. + """ + fc1 = FriendCode.objects.create( + friend_code="1111-1111-1111-1111", + user=self.user, + in_game_name="PrimaryGame" + ) + # fc1 becomes the default automatically. + self.assertEqual(self.user.default_friend_code, fc1) + fc2 = FriendCode.objects.create( + friend_code="2222-2222-2222-2222", + user=self.user, + in_game_name="SecondaryGame" + ) + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, fc1) + + +# ----------------------------- +# Form Tests +# ----------------------------- +class FriendCodeFormTests(TestCase): + def test_valid_friend_code(self): + """Ensure valid friend code is cleaned and formatted properly.""" + form_data = { + "friend_code": "1234567890123456", + "in_game_name": "GameTest" + } + form = FriendCodeForm(data=form_data) + self.assertTrue(form.is_valid()) + self.assertEqual(form.cleaned_data["friend_code"], "1234-5678-9012-3456") + + def test_invalid_friend_code_length(self): + """Friend codes with incorrect length should cause validation errors.""" + form_data = { + "friend_code": "12345", + "in_game_name": "GameTest" + } + form = FriendCodeForm(data=form_data) + self.assertFalse(form.is_valid()) + self.assertIn("Friend code must be exactly 16 digits long.", form.errors["friend_code"]) + + def test_invalid_friend_code_characters(self): + """Friend codes containing non-digit characters should cause validation errors.""" + form_data = { + "friend_code": "12345678901234ab", + "in_game_name": "GameTest" + } + form = FriendCodeForm(data=form_data) + self.assertFalse(form.is_valid()) + self.assertIn("Friend code must be exactly 16 digits long.", form.errors["friend_code"]) + + def test_friend_code_with_whitespace(self): + """Ensure that leading/trailing whitespace is stripped.""" + form_data = { + "friend_code": " 1234567890123456 ", + "in_game_name": "WhitespaceGame" + } + form = FriendCodeForm(data=form_data) + self.assertTrue(form.is_valid()) + self.assertEqual(form.cleaned_data["friend_code"], "1234-5678-9012-3456") + + def test_friend_code_with_dashes(self): + """Proper dashes in the input should be accepted.""" + form_data = { + "friend_code": "1234-5678-9012-3456", + "in_game_name": "ExtraDashGame" + } + form = FriendCodeForm(data=form_data) + self.assertTrue(form.is_valid()) + self.assertEqual(form.cleaned_data["friend_code"], "1234-5678-9012-3456") + + +class CustomUserCreationFormTests(TestCase): + def _get_request_with_session(self): + """ + Helper to create a Request object that has a session, + so that the signup view and form can use request.session. + """ + request = RequestFactory().get("/") + middleware = SessionMiddleware(lambda r: None) + middleware.process_request(request) + request.session.save() + return request + + def test_valid_custom_user_creation(self): + """ + Test that the custom sign‑up form creates a user and associated friend code properly. + """ + form_data = { + "email": "new@example.com", + "username": "newuser", + "password1": "complexpass123", + "password2": "complexpass123", + "friend_code": "5555-5555-5555-5555", + "in_game_name": "NewGame", + } + form = CustomUserCreationForm(data=form_data) + self.assertTrue(form.is_valid()) + request = self._get_request_with_session() + user = form.save(request) + self.assertIsNotNone(user) + # Check that the associated friend code exists and marked as the default. + friend_code = user.default_friend_code + self.assertIsNotNone(friend_code) + self.assertEqual(friend_code.friend_code, "5555-5555-5555-5555") + self.assertEqual(friend_code.in_game_name, "NewGame") + + def test_user_always_has_default_after_signup(self): + """ + Ensure that after sign-up (which creates the initial friend code), + the user always has a default friend code. + """ + form_data = { + "email": "another@example.com", + "username": "anotheruser", + "password1": "complexpass456", + "password2": "complexpass456", + "friend_code": "6666-6666-6666-6666", + "in_game_name": "AnotherGame", + } + form = CustomUserCreationForm(data=form_data) + self.assertTrue(form.is_valid()) + request = self._get_request_with_session() + user = form.save(request) + # Immediately after signup, the user should have a default friend code. + self.assertIsNotNone(user.default_friend_code) + + def test_invalid_custom_user_creation_invalid_friend_code(self): + """ + Supplying an invalid friend code (wrong length/format) should cause the form to fail. + """ + form_data = { + "email": "bad@example.com", + "username": "baduser", + "password1": "pass12345", + "password2": "pass12345", + "friend_code": "abcde", # Invalid friend code + "in_game_name": "BadGame", + } + form = CustomUserCreationForm(data=form_data) + self.assertFalse(form.is_valid()) + self.assertIn("Friend code must be exactly 16 digits long.", form.errors["friend_code"]) + + def test_invalid_custom_user_creation_password_mismatch(self): + """ + The form should catch mismatched passwords. + """ + form_data = { + "email": "passmismatch@example.com", + "username": "passmismatch", + "password1": "pass12345", + "password2": "differentpass", + "friend_code": "5555-5555-5555-5555", + "in_game_name": "MismatchGame", + } + form = CustomUserCreationForm(data=form_data) + self.assertFalse(form.is_valid()) + # The error key may be '__all__' or 'password2' depending on the implementation. + errors = form.errors.get("__all__") or form.errors.get("password2") + self.assertTrue(errors, "Expected a password mismatch error.") + + +class UserSettingsFormTests(TestCase): + def setUp(self): + self.user = get_user_model().objects.create_user( + username="settingsuser", + email="settings@example.com", + password="password123" + ) + + def test_toggle_show_friend_code_on_link_previews(self): + """Test updating the user setting for showing friend code on link previews.""" + form_data = {"show_friend_code_on_link_previews": True} + form = UserSettingsForm(form_data, instance=self.user) + self.assertTrue(form.is_valid()) + form.save() + self.user.refresh_from_db() + self.assertTrue(self.user.show_friend_code_on_link_previews) + + +# ----------------------------- +# View Tests +# ----------------------------- +class FriendCodeViewsTests(TestCase): + def setUp(self): + self.user = get_user_model().objects.create_user( + username="viewuser", + email="viewuser@example.com", + password="password123" + ) + # Log in this user. + self.client.login(username="viewuser", password="password123") + # Create two friend codes. + self.friend_code1 = FriendCode.objects.create( + friend_code="7777-7777-7777-7777", + user=self.user, + in_game_name="ViewGameOne" + ) + self.friend_code2 = FriendCode.objects.create( + friend_code="8888-8888-8888-8888", + user=self.user, + in_game_name="ViewGameTwo" + ) + # By default, friend_code1 is the default. + + def test_list_friend_codes_view(self): + """The list view should display all friend codes with a correct default flag.""" + url = reverse("list_friend_codes") + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + friend_codes = response.context["friend_codes"] + self.assertEqual(friend_codes.count(), 2) + for fc in friend_codes: + if fc.pk == self.friend_code1.pk: + self.assertTrue(fc.is_default) + else: + self.assertFalse(fc.is_default) + + def test_list_friend_codes_view_unauthenticated(self): + """An unauthenticated user should be redirected from the friend codes list view.""" + self.client.logout() + url = reverse("list_friend_codes") + response = self.client.get(url) + self.assertNotEqual(response.status_code, 200) + # Adjust the login URL as per your configuration. + self.assertIn("/accounts/login/", response.url) + + def test_add_friend_code_view(self): + """Test both GET and POST for adding a new friend code.""" + url = reverse("add_friend_code") + # GET request. + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + # POST request. + data = {"friend_code": "9999999999999999", "in_game_name": "ViewGameThree"} + response = self.client.post(url, data) + self.assertRedirects(response, reverse("list_friend_codes")) + self.assertTrue( + FriendCode.objects.filter( + user=self.user, + friend_code="9999-9999-9999-9999" + ).exists() + ) + # Ensure that adding a new friend code does not change the default. + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code, self.friend_code1) + + def test_add_friend_code_view_invalid_data(self): + """Submitting invalid friend code data should not create a new record.""" + url = reverse("add_friend_code") + data = {"friend_code": "invalidfriendcode", "in_game_name": "InvalidGame"} + response = self.client.post(url, data) + # Extract the form from the response's context. If response.context is a list, use its first element. + context = response.context[0] if isinstance(response.context, list) else response.context + form = context.get("form") + self.assertIsNotNone(form, "Form not found in response context") + self.assertFormError(form, "friend_code", "Friend code must be exactly 16 digits long.") + + def test_edit_friend_code_view(self): + """Test editing the in-game name of an existing friend code.""" + url = reverse("edit_friend_code", kwargs={"pk": self.friend_code2.pk}) + # GET request. + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + # POST request. + new_data = {"in_game_name": "UpdatedViewGame"} + response = self.client.post(url, new_data) + self.assertEqual(response.status_code, 302) + self.friend_code2.refresh_from_db() + self.assertEqual(self.friend_code2.in_game_name, "UpdatedViewGame") + + def test_edit_friend_code_view_wrong_user(self): + """A user should not be able to edit a friend code that does not belong to them.""" + other_user = get_user_model().objects.create_user( + username="otheruser", + email="other@example.com", + password="password1234" + ) + friend_code_other = FriendCode.objects.create( + friend_code="0000-0000-0000-0000", + user=other_user, + in_game_name="OtherGame" + ) + url = reverse("edit_friend_code", kwargs={"pk": friend_code_other.pk}) + response = self.client.get(url) + self.assertEqual(response.status_code, 404) + + def test_edit_friend_code_view_invalid_data(self): + """Invalid POST data for editing friend code should result in form errors.""" + url = reverse("edit_friend_code", kwargs={"pk": self.friend_code2.pk}) + new_data = {"in_game_name": ""} # in_game_name is required. + response = self.client.post(url, new_data) + context = response.context[0] if isinstance(response.context, list) else response.context + form = context.get("form") + self.assertIsNotNone(form, "Form not found in response context") + self.assertFormError(form, "in_game_name", "This field is required.") + + def test_delete_friend_code_view_only_code(self): + """ + If the user has only one friend code, deletion should be disabled. + This test uses a new user with a single friend code. + """ + user_only = get_user_model().objects.create_user( + username="onlyuser", + email="onlyuser@example.com", + password="password123" + ) + friend_code_only = FriendCode.objects.create( + friend_code="4444-4444-4444-4444", + user=user_only, + in_game_name="SoloGame" + ) + self.client.logout() + self.client.login(username="onlyuser", password="password123") + url = reverse("delete_friend_code", kwargs={"pk": friend_code_only.pk}) + # GET request: deletion should be disabled. + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertIn("disable_delete", response.context) + self.assertTrue(response.context["disable_delete"]) + # POST request should not delete the friend code. + response = self.client.post(url, {}) + self.assertRedirects(response, reverse("list_friend_codes")) + self.assertTrue(FriendCode.objects.filter(pk=friend_code_only.pk).exists()) + + def test_delete_friend_code_view_default_code(self): + """Deleting the default friend code should be prevented.""" + url = reverse("delete_friend_code", kwargs={"pk": self.friend_code1.pk}) + response = self.client.post(url, {}) + self.assertRedirects(response, reverse("list_friend_codes")) + self.assertTrue(FriendCode.objects.filter(pk=self.friend_code1.pk).exists()) + + def test_delete_friend_code_view_with_trade_offers(self): + """ + If a friend code is associated with trade offers, deletion should be blocked. + Instead of direct assignment, we patch the `exists` methods on the related managers. + """ + self.trade_offer = TradeOffer.objects.create( + initiated_by=self.friend_code2, + is_closed=False, + rarity_icon="⭐️", + rarity_level=5 + ) + url = reverse("delete_friend_code", kwargs={"pk": self.friend_code2.pk}) + response = self.client.post(url, {}) + self.assertRedirects(response, reverse("list_friend_codes")) + self.assertTrue(FriendCode.objects.filter(pk=self.friend_code2.pk).exists()) + self.trade_offer.delete() + + def test_change_default_friend_code_view(self): + """Test that a POST to change the default friend code updates the user setting.""" + url = reverse("change_default_friend_code", kwargs={"pk": self.friend_code2.pk}) + response = self.client.post(url, {}) + self.assertRedirects(response, reverse("list_friend_codes")) + self.user.refresh_from_db() + self.assertEqual(self.user.default_friend_code.pk, self.friend_code2.pk) + + def test_change_default_friend_code_view_invalid_friend_code(self): + """Posting a non-existent friend code id should return a 404 error.""" + url = reverse("change_default_friend_code", kwargs={"pk": 99999}) + response = self.client.post(url, {}) + self.assertEqual(response.status_code, 404) + + def test_change_default_friend_code_view_not_owned(self): + """A friend code that does not belong to the current user should result in a 404.""" + other_user = get_user_model().objects.create_user( + username="otheruser2", + email="other2@example.com", + password="password789" + ) + friend_code_other = FriendCode.objects.create( + friend_code="1111-1111-1111-1111", + user=other_user, + in_game_name="NotMine" + ) + url = reverse("change_default_friend_code", kwargs={"pk": friend_code_other.pk}) + response = self.client.post(url, {}) + self.assertEqual(response.status_code, 404) + + def test_settings_view(self): + """Settings view should allow updating of user settings.""" + url = reverse("settings") + # GET request. + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + # POST request. + data = {"show_friend_code_on_link_previews": True} + response = self.client.post(url, data) + self.assertRedirects(response, reverse("settings")) + self.user.refresh_from_db() + self.assertTrue(self.user.show_friend_code_on_link_previews) + + def test_profile_view(self): + """Profile page should be accessible for authenticated users.""" + url = reverse("profile") + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + def test_profile_view_unauthenticated(self): + """Unauthenticated users should be redirected from the profile page.""" + self.client.logout() + url = reverse("profile") + response = self.client.get(url) + self.assertNotEqual(response.status_code, 200) + + def test_delete_friend_code_view_wrong_user(self): + """A user should not be able to delete a friend code that does not belong to them.""" + other_user = get_user_model().objects.create_user( + username="otherdeluser", + email="otherdel@example.com", + password="password321" + ) + friend_code_other = FriendCode.objects.create( + friend_code="2222-2222-2222-2222", + user=other_user, + in_game_name="OtherDelete" + ) + url = reverse("delete_friend_code", kwargs={"pk": friend_code_other.pk}) + response = self.client.get(url) + self.assertEqual(response.status_code, 404) + + +# ----------------------------- +# Template Tags Tests +# ----------------------------- +class TemplateTagTests(TestCase): + def test_gravatar_hash(self): + """Test that gravatar_hash returns the correct SHA256 hash.""" + email = "Test@Example.com" + expected = hashlib.sha256(email.strip().lower().encode("utf-8")).hexdigest() + result = gravatar.gravatar_hash(email) + self.assertEqual(result, expected) + + def test_gravatar_url(self): + """Ensure gravatar_url returns a URL with the proper parameters.""" + email = "user@example.com" + size = 100 + url = gravatar.gravatar_url(email, size) + self.assertIn("s=100", url) + self.assertIn("https://www.gravatar.com/avatar/", url) + + def test_gravatar_profile_url_with_none(self): + """Test gravatar_profile_url returns the generic profile URL if no email is provided.""" + url = gravatar.gravatar_profile_url() + self.assertEqual(url, "https://www.gravatar.com/profile") + + def test_gravatar_filter(self): + """Test that the gravatar filter returns an HTML image tag with expected attributes.""" + email = "user@example.com" + size = 50 + result = gravatar.gravatar(email, size) + self.assertIn('img src="', result) + self.assertIn(f'width="{size}"', result) + + @patch("accounts.templatetags.gravatar.requests.get") + def test_gravatar_profile_data_success(self, mock_get): + """Test that gravatar_profile_data returns the first entry when JSON response is valid.""" + dummy_entry = {"name": "Test User"} + mock_response = MagicMock() + mock_response.json.return_value = {"entry": [dummy_entry]} + mock_response.raise_for_status.return_value = None + mock_get.return_value = mock_response + data = gravatar.gravatar_profile_data("user@example.com") + self.assertEqual(data, dummy_entry) + + @patch("accounts.templatetags.gravatar.requests.get") + def test_gravatar_profile_data_failure(self, mock_get): + """ + If requests.get fails or the JSON is not valid, + gravatar_profile_data should return an empty dictionary. + """ + mock_get.side_effect = requests.RequestException("Request failed") + data = gravatar.gravatar_profile_data("user@example.com") + self.assertEqual(data, {}) + + def test_gravatar_no_hover(self): + """Test that gravatar_no_hover returns an image tag with the additional 'ignore' class.""" + email = "hover@example.com" + result = gravatar.gravatar_no_hover(email, 30) + self.assertIn('class="ignore"', result) + + def test_gravatar_filter_with_empty_string(self): + """Even if an empty email is passed, the gravatar filter should return an image tag.""" + result = gravatar.gravatar("", 40) + self.assertIn('img src="', result) diff --git a/accounts/views.py b/accounts/views.py index b810eca..354235e 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -6,6 +6,7 @@ from django.views.generic import ListView, CreateView, DeleteView, View, Templat from accounts.models import FriendCode, CustomUser from accounts.forms import FriendCodeForm, UserSettingsForm from django.db.models import Case, When, Value, BooleanField +from trades.models import TradeOffer, TradeAcceptance class ListFriendCodesView(LoginRequiredMixin, ListView): """ @@ -99,8 +100,11 @@ class DeleteFriendCodeView(LoginRequiredMixin, DeleteView): ) return redirect(self.success_url) - # Also check if this friend code is referenced by any trade offer. - if self.object.initiated_trade_offers.exists() or self.object.trade_acceptances.exists(): + # Use the unfiltered manager and filter by the friend code's primary key + trade_offer_exists = TradeOffer.all_offers.filter(initiated_by_id=self.object.pk).exists() + trade_acceptance_exists = TradeAcceptance.objects.filter(accepted_by_id=self.object.pk).exists() + + if trade_offer_exists or trade_acceptance_exists: messages.error( request, "Cannot remove this friend code because there are existing trade offers associated with it." @@ -110,7 +114,7 @@ class DeleteFriendCodeView(LoginRequiredMixin, DeleteView): # Proceed to safe deletion. self.object.delete() messages.success(request, "Friend code removed successfully.") - return redirect(self.success_url + "?deleted=true") + return redirect(self.success_url) class ChangeDefaultFriendCodeView(LoginRequiredMixin, View): """ diff --git a/django_project/settings.py b/django_project/settings.py index 6bc0b5a..0fbda05 100644 --- a/django_project/settings.py +++ b/django_project/settings.py @@ -55,7 +55,7 @@ INSTALLED_APPS = [ "accounts", "cards", "home", - "trades.apps.TradesConfig", + "trades", "meta", ] diff --git a/trades/models.py b/trades/models.py index 9752663..b251a35 100644 --- a/trades/models.py +++ b/trades/models.py @@ -25,8 +25,14 @@ class TradeOfferManager(models.Manager): qs = qs.filter(created_at__gte=cutoff) return qs.order_by("-updated_at") +class TradeOfferAllManager(models.Manager): + def get_queryset(self): + # Return all trade offers without filtering by the cutoff. + return super().get_queryset() + class TradeOffer(models.Model): objects = TradeOfferManager() + all_offers = TradeOfferAllManager() # New unfiltered manager id = models.AutoField(primary_key=True) is_closed = models.BooleanField(default=False, db_index=True)