mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	create_user: Handle integrity error when importing settings.
During account creation when a user opted to import settings from an existing account, the "Mark visibility_policy_banner as read" step was raising integrity error. It is because 'copy_onboarding_steps' is already executed earlier in the 'do_create_user' codeflow. If the source profile had already marked 'visibility_policy_banner' as read, we were facing integrity error. This commit fixes the bug.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							555ac613ac
						
					
				
				
					commit
					fdf90f7ad1
				
			@@ -1,10 +1,11 @@
 | 
				
			|||||||
from collections import defaultdict
 | 
					from collections import defaultdict
 | 
				
			||||||
from collections.abc import Iterable, Sequence
 | 
					from collections.abc import Iterable, Sequence
 | 
				
			||||||
 | 
					from contextlib import suppress
 | 
				
			||||||
from datetime import timedelta
 | 
					from datetime import timedelta
 | 
				
			||||||
from typing import Any
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.db import transaction
 | 
					from django.db import IntegrityError, transaction
 | 
				
			||||||
from django.db.models import F
 | 
					from django.db.models import F
 | 
				
			||||||
from django.utils.timezone import now as timezone_now
 | 
					from django.utils.timezone import now as timezone_now
 | 
				
			||||||
from django.utils.translation import gettext as _
 | 
					from django.utils.translation import gettext as _
 | 
				
			||||||
@@ -351,6 +352,16 @@ def process_new_human_user(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    # The 'visibility_policy_banner' is only displayed to existing users.
 | 
					    # The 'visibility_policy_banner' is only displayed to existing users.
 | 
				
			||||||
    # Mark it as read for a new user.
 | 
					    # Mark it as read for a new user.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # If the new user opted to import settings from an existing account, and
 | 
				
			||||||
 | 
					    # 'visibility_policy_banner' is already marked as read for the existing account,
 | 
				
			||||||
 | 
					    # 'copy_onboarding_steps' function already did the needed copying.
 | 
				
			||||||
 | 
					    # Simply ignore the IntegrityError in that case.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # The extremely brief nature of this subtransaction makes a savepoint safe.
 | 
				
			||||||
 | 
					    # See https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful
 | 
				
			||||||
 | 
					    # for context on risks around savepoints.
 | 
				
			||||||
 | 
					    with suppress(IntegrityError), transaction.atomic(savepoint=True):
 | 
				
			||||||
        OnboardingStep.objects.create(user=user_profile, onboarding_step="visibility_policy_banner")
 | 
					        OnboardingStep.objects.create(user=user_profile, onboarding_step="visibility_policy_banner")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,6 +67,7 @@ from zerver.models import (
 | 
				
			|||||||
    CustomProfileFieldValue,
 | 
					    CustomProfileFieldValue,
 | 
				
			||||||
    DefaultStream,
 | 
					    DefaultStream,
 | 
				
			||||||
    Message,
 | 
					    Message,
 | 
				
			||||||
 | 
					    OnboardingStep,
 | 
				
			||||||
    OnboardingUserMessage,
 | 
					    OnboardingUserMessage,
 | 
				
			||||||
    PreregistrationRealm,
 | 
					    PreregistrationRealm,
 | 
				
			||||||
    PreregistrationUser,
 | 
					    PreregistrationUser,
 | 
				
			||||||
@@ -2826,6 +2827,9 @@ class UserSignUpTest(ZulipTestCase):
 | 
				
			|||||||
        hamlet_in_zulip.email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE
 | 
					        hamlet_in_zulip.email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE
 | 
				
			||||||
        hamlet_in_zulip.save()
 | 
					        hamlet_in_zulip.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OnboardingStep.objects.filter(user=hamlet_in_zulip).delete()
 | 
				
			||||||
 | 
					        OnboardingStep.objects.create(user=hamlet_in_zulip, onboarding_step="intro_resolve_topic")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = self.client_post("/accounts/home/", {"email": email}, subdomain=subdomain)
 | 
					        result = self.client_post("/accounts/home/", {"email": email}, subdomain=subdomain)
 | 
				
			||||||
        self.assertEqual(result.status_code, 302)
 | 
					        self.assertEqual(result.status_code, 302)
 | 
				
			||||||
        result = self.client_get(result["Location"], subdomain=subdomain)
 | 
					        result = self.client_get(result["Location"], subdomain=subdomain)
 | 
				
			||||||
@@ -2844,6 +2848,12 @@ class UserSignUpTest(ZulipTestCase):
 | 
				
			|||||||
        self.assertEqual(hamlet.high_contrast_mode, False)
 | 
					        self.assertEqual(hamlet.high_contrast_mode, False)
 | 
				
			||||||
        self.assertEqual(hamlet.enable_stream_audible_notifications, False)
 | 
					        self.assertEqual(hamlet.enable_stream_audible_notifications, False)
 | 
				
			||||||
        self.assertEqual(hamlet.enter_sends, False)
 | 
					        self.assertEqual(hamlet.enter_sends, False)
 | 
				
			||||||
 | 
					        # 'visibility_policy_banner' is marked as read in 'process_new_human_user'.
 | 
				
			||||||
 | 
					        # 'copy_default_settings' is not executed as the user decided to NOT import
 | 
				
			||||||
 | 
					        # settings from another realm, hence 'intro_resolve_topic' not marked as seen.
 | 
				
			||||||
 | 
					        onboarding_steps = OnboardingStep.objects.filter(user=hamlet)
 | 
				
			||||||
 | 
					        self.assertEqual(onboarding_steps.count(), 1)
 | 
				
			||||||
 | 
					        self.assertEqual(onboarding_steps[0].onboarding_step, "visibility_policy_banner")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_signup_with_user_settings_from_another_realm(self) -> None:
 | 
					    def test_signup_with_user_settings_from_another_realm(self) -> None:
 | 
				
			||||||
        hamlet_in_zulip = self.example_user("hamlet")
 | 
					        hamlet_in_zulip = self.example_user("hamlet")
 | 
				
			||||||
@@ -2864,6 +2874,12 @@ class UserSignUpTest(ZulipTestCase):
 | 
				
			|||||||
        hamlet_in_zulip.email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE
 | 
					        hamlet_in_zulip.email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE
 | 
				
			||||||
        hamlet_in_zulip.save()
 | 
					        hamlet_in_zulip.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OnboardingStep.objects.filter(user=hamlet_in_zulip).delete()
 | 
				
			||||||
 | 
					        OnboardingStep.objects.create(user=hamlet_in_zulip, onboarding_step="intro_resolve_topic")
 | 
				
			||||||
 | 
					        OnboardingStep.objects.create(
 | 
				
			||||||
 | 
					            user=hamlet_in_zulip, onboarding_step="visibility_policy_banner"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Now we'll be making requests to another subdomain, so we need to logout
 | 
					        # Now we'll be making requests to another subdomain, so we need to logout
 | 
				
			||||||
        # to avoid polluting the session in the test environment by still being
 | 
					        # to avoid polluting the session in the test environment by still being
 | 
				
			||||||
        # logged in.
 | 
					        # logged in.
 | 
				
			||||||
@@ -2909,6 +2925,13 @@ class UserSignUpTest(ZulipTestCase):
 | 
				
			|||||||
        self.assertEqual(
 | 
					        self.assertEqual(
 | 
				
			||||||
            hamlet_in_lear.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY
 | 
					            hamlet_in_lear.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        # Verify that 'copy_default_settings' copies the onboarding steps.
 | 
				
			||||||
 | 
					        onboarding_steps = OnboardingStep.objects.filter(user=hamlet_in_lear)
 | 
				
			||||||
 | 
					        self.assertEqual(onboarding_steps.count(), 2)
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            set(onboarding_steps.values_list("onboarding_step", flat=True)),
 | 
				
			||||||
 | 
					            {"intro_resolve_topic", "visibility_policy_banner"},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        zulip_path_id = avatar_disk_path(hamlet_in_zulip)
 | 
					        zulip_path_id = avatar_disk_path(hamlet_in_zulip)
 | 
				
			||||||
        lear_path_id = avatar_disk_path(hamlet_in_lear)
 | 
					        lear_path_id = avatar_disk_path(hamlet_in_lear)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user