def test_parse_services(self): self.assertEquals( ('ikea:%22Stuff%22/Hello+There', 'service_id'), identifiers.parse(' Ikea :%22Stuff%22/Hello%20There ')) self.assertEquals(('ikea:%22Stuff%22/Hello+There', 'service_id'), identifiers.parse('ikea:"Stuff"/Hello+There')) self.assertEquals(('spotify:BOB', 'service_id'), identifiers.parse('SPOTIFY:BOB'))
def connect_email(handler): for identifier in handler.identifiers: identifier, identifier_type = identifiers.parse(identifier) if identifier_type != identifiers.EMAIL: continue _, team, user = identifiers.parse_service(identifier) handler.connect_service('email', team, user)
def get_handler(identifier): """Returns an account handler for the given identifier.""" if isinstance(identifier, AccountHandler): # Assume that account handlers have already been resolved before. return identifier # Parse and normalize the identifier. identifier_type = 'unknown' if isinstance(identifier, basestring): identifier, identifier_type = identifiers.parse(identifier) # Attempt to find a Roger account for the provided identifier. account = models.Account.resolve(identifier) if account: # First check if there is a static handler for the account. for identity in account.identifiers: cls = _static_handlers.get(identity.id()) if cls: return cls.handler # Support custom handlers for specific statuses. if account.status in _status_handlers: return _status_handlers[account.status](account) # No special handling for this account. return AccountHandler(account) # Finally check if the identifier has a static handler. if identifier in _static_handlers: # Use a static handler for this identifier. return _static_handlers[identifier].handler # Give up. logging.info('Could not get a handler for "%s" (%s)', identifier, identifier_type) raise errors.ResourceNotFound('That account does not exist')
def change_identifier(self, old, new, notify_connect=True, primary=False): new, identifier_type = identifiers.parse(new) if not new: logging.warning('%r is invalid', new) raise errors.InvalidArgument('That identifier is not valid') if old not in self.identifiers: raise errors.ForbiddenAction('That identifier belongs to another account') if old == new: return # Get the service, team, resource from the new identifier. try: service, team, resource = identifiers.parse_service(new) new_team = not self.is_on_team(service, team) except: service, team, resource = (None, None, None) new_team = True identity, account = models.Identity.change( old, new, assert_account_key=self.account.key, primary=primary) if not identity: raise errors.AlreadyExists('That identifier is already in use') # Update in-memory instance to reflect reality. if account: self.account.populate(**account.to_dict()) if self.account.is_activated and service == 'email' and new_team: # Connect the email "service" (if the user is not already on this domain). self.connect_service(service, team, resource, notify=notify_connect) # TODO: We should also disconnect service if the old identifier was a service. self._notify_account_change()
def add_identifier(self, identifier, notify_change=True, notify_connect=True, **kwargs): identifier, identifier_type = identifiers.parse(identifier) identity, account = models.Identity.add(identifier, self.account.key, **kwargs) if not identity: if self.has_identifier(identifier): # Just assume the identifier is already owned by the current account. return raise errors.AlreadyExists('That identifier is already in use') # Brazil can use two formats for one phone number. equivalent = self._get_alternate_identifier(identity.key.id()) if equivalent: i, a = models.Identity.add(equivalent, self.account.key) if i and a: identity, account = i, a else: logging.warning('Failed to reserve %r (based on %r) for %d', equivalent, identifier, self.account.key.id()) # Update in-memory instance to reflect reality. self.account.populate(**account.to_dict()) if identifier_type == identifiers.EMAIL and self.account.is_activated: # Connect the email "service". _, team, user = identifiers.parse_service(identifier) self.connect_service('email', team, user, notify=notify_connect) elif identifier_type == identifiers.SERVICE_ID: service, team, user = identifiers.parse_service(identifier) if service == 'fika': # fika.io "service" always gets connected. self.connect_service('fika', team, user, notify=notify_connect) if notify_change: self._notify_account_change()
def test_parse_username(self): self.assertEquals(('a', 'username'), identifiers.parse('a')) self.assertEquals(('ab', 'username'), identifiers.parse('ab')) self.assertEquals(('a1', 'username'), identifiers.parse('a1')) self.assertEquals(('a1b', 'username'), identifiers.parse('a1b')) self.assertEquals(('a1b0', 'username'), identifiers.parse('a1b0')) self.assertEquals(('a1b0', 'username'), identifiers.parse('a1B0')) self.assertEquals(('a_1b-0', 'username'), identifiers.parse('a_1B-0')) self.assertEquals(('a_1b-0', 'username'), identifiers.parse('a_1B-0 ')) self.assertEquals( ('z1234567890z1234567890z1234567890z1234567890z1234567890', 'username'), identifiers.parse( 'z1234567890z1234567890z1234567890z1234567890z1234567890'))
def test_parse_account_id(self): self.assertEquals((1, 'account_id'), identifiers.parse(1)) self.assertEquals((123, 'account_id'), identifiers.parse(123)) self.assertEquals((1, 'account_id'), identifiers.parse('1')) self.assertEquals((111, 'account_id'), identifiers.parse('111')) self.assertEquals((111, 'account_id'), identifiers.parse(' 111')) self.assertEquals((111, 'account_id'), identifiers.parse(' 111')) self.assertEquals((111, 'account_id'), identifiers.parse('111 ')) self.assertEquals((111, 'account_id'), identifiers.parse(' 111 ')) self.assertEquals( (123456789012345678901234567890123456789012345678901234567890, 'account_id'), identifiers.parse( '123456789012345678901234567890123456789012345678901234567890') )
def set_username(self, new_username): new_username, identifier_type = identifiers.parse(new_username) if identifier_type != identifiers.USERNAME: # A user may not use this endpoint to add a phone number/e-mail. raise errors.InvalidArgument('A valid username must be provided') # Switch out the old username if it exists, otherwise just add the new one. old_username = self.username if old_username and self.account.primary_set: self.change_identifier(old_username, new_username, primary=True) else: self.add_identifier(new_username, primary=True)
def get_challenger(client, identifier, call=False): """ Returns a handler for creating a challenge for the given identifier. """ identifier, identifier_type = identifiers.parse(identifier) if identifier in config.DEMO_ACCOUNTS: # Demo accounts. return DummyChallenger(client, identifier) if identifier_type == identifiers.PHONE and call: return CallChallenger(client, identifier) challenger = _challengers.get(identifier_type) if not challenger: logging.warning('Failed to get a challenger for %r', identifier) raise errors.InvalidArgument('That identifier is not valid') return challenger(client, identifier)
def remove_identifier(self, identifier): if identifier not in self.identifiers: raise errors.ForbiddenAction('That identifier belongs to another account') if len(self.identifiers) < 2: raise errors.ForbiddenAction('Can not remove last identifier') account = models.Identity.release(identifier, assert_account_key=self.account.key) # Update in-memory instance to reflect reality. if account: self.account.populate(**account.to_dict()) # Disconnect service if the identifier is a service identifier. identifier, identifier_type = identifiers.parse(identifier) if identifier_type in (identifiers.EMAIL, identifiers.SERVICE_ID): service, team, resource = identifiers.parse_service(identifier) self.disconnect_service(service, team, resource) self._notify_account_change()
def parse(cls, value): if not isinstance(value, basestring): raise TypeError('Destination value must be a string') destination = cls() # Value is a comma separated list of routes. for route in value.split(','): # Route can contain a label prefix (with a colon to separate it). label_and_route = route.split(':', 1) if len(label_and_route) == 1: label = None route = label_and_route[0] else: label = re.sub(r'[\W_]', '', label_and_route[0].lower()) route = label_and_route[1] # Clean up route and get its type. route, route_type = identifiers.parse(route) destination.add_route(route_type, route, label) return destination
def test_parse_email(self): self.assertEquals(('email:example.com/niceandsimple', 'email'), identifiers.parse('*****@*****.**')) self.assertEquals(('email:example.com/very.common', 'email'), identifiers.parse('*****@*****.**')) self.assertEquals( ('email:dept.example.com/a.little.lengthy.but.fine', 'email'), identifiers.parse('*****@*****.**')) self.assertEquals( ('email:example.com/disposable.style.email.with%2Bsymbol', 'email'), identifiers.parse( '*****@*****.**')) self.assertEquals( ('email:example.com/other.email-with-dash', 'email'), identifiers.parse('*****@*****.**')) self.assertEquals( ('email:example.com/%22much.moreunusual%22', 'email'), identifiers.parse('"much.more unusual"@example.com')) self.assertEquals( ('email:example.com/%22very.unusual.%40.unusual.com%22', 'email'), identifiers.parse('"*****@*****.**"@example.com')) self.assertEquals( ('email:strange.example.com/%22very.%28%29%2C%3A%3B%3C%3E%5B%5D%22.very.%22very%40%5C%22very%22.unusual%22', 'email'), identifiers.parse( '"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com' )) self.assertEquals(( 'email:example.org/%21%23%24%25%26%27%2A%2B-%2F%3D%3F%5E_%60%7B%7D%7C%7E', 'email'), identifiers.parse('!#$%&\'*+-/=?^_`{}|[email protected]')) self.assertEquals( ('email:example.org/%22%28%29%3C%3E%5B%5D%3A%2C%3B%40%5C%22%21%23%24%25%26%27%2A%2B-%2F%3D%3F%5E_%60%7B%7D%7C%7E.a%22', 'email'), identifiers.parse( '"()<>[]:,;@\\\"!#$%&\'*+-/=?^_`{}| ~.a"@example.org')) self.assertEquals(('email:example.org/%22%22', 'email'), identifiers.parse('" "@example.org')) self.assertEquals( ('email:example.com/%C3%BC%C3%B1%C3%AE%C3%A7%C3%B8%C3%B0%C3%A9', 'email'), identifiers.parse('üñîçøðé@example.com')) self.assertEquals(( 'email:%C3%BC%C3%B1%C3%AE%C3%A7%C3%B8%C3%B0%C3%A9.com/%C3%BC%C3%B1%C3%AE%C3%A7%C3%B8%C3%B0%C3%A9', 'email'), identifiers.parse('üñîçøðé@üñîçøðé.com')) self.assertEquals(('email:b.c/a', 'email'), identifiers.parse('[email protected]')) self.assertEquals(('email:2.3/1', 'email'), identifiers.parse('[email protected]')) self.assertEquals(('email:b.c/a', 'email'), identifiers.parse(' [email protected] ')) self.assertEquals(('email:b.c/a', 'email'), identifiers.parse(' [email protected] ')) self.assertEquals(('email:b.com/a%2B1', 'email'), identifiers.parse('*****@*****.**')) self.assertEquals( ('email:weird-long-host.com.br/this-is-a-really-long-email-with%2Bfilters', 'email'), identifiers.parse( '*****@*****.**' ))
def test_parse_channel(self): self.assertEquals(('#yolo', 'channel'), identifiers.parse('#yolo')) self.assertEquals(('#123', 'channel'), identifiers.parse('#123')) self.assertEquals(('#2pac', 'channel'), identifiers.parse('#2pac')) self.assertEquals(('#pac2', 'channel'), identifiers.parse('#pac2')) self.assertEquals(('#2', 'channel'), identifiers.parse('#2')) self.assertEquals(('#a', 'channel'), identifiers.parse('#a')) self.assertEquals(('#+123', 'channel'), identifiers.parse('#+123')) self.assertEquals(('#+1239415487', 'channel'), identifiers.parse('#+1239415487')) self.assertEquals(('#[email protected]', 'channel'), identifiers.parse('#[email protected]')) self.assertEquals(('#✂✒✏', 'channel'), identifiers.parse('#✂✒✏')) self.assertEquals(('#@!-k', 'channel'), identifiers.parse('#@!-k')) self.assertEquals(('#阿里巴巴集团', 'channel'), identifiers.parse('#阿里巴巴集团')) self.assertEquals(('#❤💔💗💓💕💖💞💘💌💋💍💎👤👥💬👣💭', 'channel'), identifiers.parse('#❤💔💗💓💕💖💞💘💌💋💍💎👤👥💬👣💭'))
def test_parse_phone(self): self.assertEquals(('+123456', 'phone'), identifiers.parse('+123456')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+1 2 3 4 5 6')) self.assertEquals(('+1234567890', 'phone'), identifiers.parse('+1 (234) 56-7890')) self.assertEquals(('+123456789012345678901234567890', 'phone'), identifiers.parse('+123456789012345678901234567890')) self.assertEquals( ('+123456789012345678901234567890', 'phone'), identifiers.parse('+1 (234) 56-789012345678901234567890')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+123456abc')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+123abc456')) self.assertEquals(('+1239415487', 'phone'), identifiers.parse('++1239415487')) self.assertEquals(('+1239415487', 'phone'), identifiers.parse('+#1239415487')) self.assertEquals(('+1239415487', 'phone'), identifiers.parse('+@1239415487')) self.assertEquals(('+123456', 'phone'), identifiers.parse('*****@*****.**')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+✂1✒2✏3 4 56 ')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+12@34!5-6k')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+阿里123456巴巴集团')) self.assertEquals(('+123456', 'phone'), identifiers.parse('+❤1💔2💗3💓4💕5💖6💞💘💌💋💍💎👤👥💬👣💭'))
def test_parse_email_service(self): self.assertEquals(('email:b.c/a', 'email'), identifiers.parse(' email:B.C/A ')) self.assertEquals(('email:b.c/a%2Bb%2Bxyz', 'email'), identifiers.parse(' email:B.C/A%2Bb%2BXYZ '))