mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	performance: Optimize get_realm_email_validator.
We now query RealmDomain objects up front. This change is minor in most circumstances--it sometimes saves a round trip to the database; other times, it actually brings back slightly more data (optimistically). The big win will come in a subsequent commit, where we avoid running these queries in a loop for every callback. Note that I'm not sure if we intentionally omitted checks for emails with "+" in them for some circumstances, but I just preserved the behavior.
This commit is contained in:
		@@ -575,28 +575,69 @@ class EmailContainsPlusError(Exception):
 | 
			
		||||
# So for invite-only realms, this is the test for whether a user can be invited,
 | 
			
		||||
# not whether the user can sign up currently.)
 | 
			
		||||
def email_allowed_for_realm(email: str, realm: Realm) -> None:
 | 
			
		||||
    '''
 | 
			
		||||
    Avoid calling this in a loop!
 | 
			
		||||
    Instead, call get_realm_email_validator()
 | 
			
		||||
    outside of the loop.
 | 
			
		||||
    '''
 | 
			
		||||
    get_realm_email_validator(realm)(email)
 | 
			
		||||
 | 
			
		||||
def get_realm_email_validator(realm: Realm) -> Callable[[str], None]:
 | 
			
		||||
    def validate(email: str) -> None:
 | 
			
		||||
        if not realm.emails_restricted_to_domains:
 | 
			
		||||
            if realm.disallow_disposable_email_addresses and \
 | 
			
		||||
                    is_disposable_domain(email_to_domain(email)):
 | 
			
		||||
def validate_disposable(email: str) -> None:
 | 
			
		||||
    if is_disposable_domain(email_to_domain(email)):
 | 
			
		||||
        raise DisposableEmailError
 | 
			
		||||
            return
 | 
			
		||||
        elif '+' in email_to_username(email):
 | 
			
		||||
 | 
			
		||||
def get_realm_email_validator(realm: Realm) -> Callable[[str], None]:
 | 
			
		||||
    if not realm.emails_restricted_to_domains:
 | 
			
		||||
        # Should we also do '+' check for non-resticted realms?
 | 
			
		||||
        if realm.disallow_disposable_email_addresses:
 | 
			
		||||
            return validate_disposable
 | 
			
		||||
 | 
			
		||||
        # allow any email through
 | 
			
		||||
        return lambda email: None
 | 
			
		||||
 | 
			
		||||
    '''
 | 
			
		||||
    RESTRICTIVE REALMS:
 | 
			
		||||
 | 
			
		||||
    Some realms only allow emails within a set
 | 
			
		||||
    of domains that are configured in RealmDomain.
 | 
			
		||||
 | 
			
		||||
    We get the set of domains up front so that
 | 
			
		||||
    folks can validate multiple emails without
 | 
			
		||||
    multiple round trips to the database.
 | 
			
		||||
    '''
 | 
			
		||||
 | 
			
		||||
    query = RealmDomain.objects.filter(realm=realm)
 | 
			
		||||
    rows = list(query.values('allow_subdomains', 'domain'))
 | 
			
		||||
 | 
			
		||||
    allowed_domains = {
 | 
			
		||||
        r['domain'] for r in rows
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    allowed_subdomains = {
 | 
			
		||||
        r['domain'] for r in rows
 | 
			
		||||
        if r['allow_subdomains']
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def validate(email: str) -> None:
 | 
			
		||||
        '''
 | 
			
		||||
        We don't have to do a "disposable" check for restricted
 | 
			
		||||
        domains, since the realm is already giving us
 | 
			
		||||
        a small whitelist.
 | 
			
		||||
        '''
 | 
			
		||||
 | 
			
		||||
        if '+' in email_to_username(email):
 | 
			
		||||
            raise EmailContainsPlusError
 | 
			
		||||
 | 
			
		||||
        domain = email_to_domain(email)
 | 
			
		||||
        query = RealmDomain.objects.filter(realm=realm)
 | 
			
		||||
        if query.filter(domain=domain).exists():
 | 
			
		||||
 | 
			
		||||
        if domain in allowed_domains:
 | 
			
		||||
            return
 | 
			
		||||
        else:
 | 
			
		||||
            query = query.filter(allow_subdomains=True)
 | 
			
		||||
 | 
			
		||||
        while len(domain) > 0:
 | 
			
		||||
            subdomain, sep, domain = domain.partition('.')
 | 
			
		||||
                if query.filter(domain=domain).exists():
 | 
			
		||||
            if domain in allowed_subdomains:
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
        raise DomainNotAllowedForRealmError
 | 
			
		||||
 | 
			
		||||
    return validate
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user