def testIsValidEmail(self): """Tests the Email validator class.""" for email in self.GOOD_EMAIL_ADDRESSES: self.assertTrue(validate.IsValidEmail(email), msg='Rejected:%r' % email) for email in self.BAD_EMAIL_ADDRESSES: self.assertFalse(validate.IsValidEmail(email), msg='Accepted:%r' % email)
def LinkifyEmail(_mr, autolink_regex_match, component_ref_artifacts): """Examine a textual reference and replace it with a hyperlink or not. This is a callback for use with the autolink feature. The function parameters are standard for this type of callback. Args: _mr: unused information parsed from the HTTP request. autolink_regex_match: regex match for the textual reference. component_ref_artifacts: result of call to GetReferencedUsers. Returns: A list of TextRuns with tag=a linking to the user profile page of any defined users, otherwise a mailto: link is generated. """ email = autolink_regex_match.group(0) if not validate.IsValidEmail(email): return [template_helpers.TextRun(email)] if component_ref_artifacts and email in component_ref_artifacts: href = '/u/%s' % email else: href = 'mailto:' + email result = [template_helpers.TextRun(email, tag='a', href=href)] return result
def LookupUserIDs(self, cnxn, emails, autocreate=False, allowgroups=False): """Return a dict of user IDs for the given emails. Args: cnxn: connection to SQL database. emails: list of string email addresses. autocreate: set to True to create users that were not found. allowgroups: set to True to allow non-email user name for group creation. Returns: A dict {email_addr: user_id} for the requested emails. Raises: exceptions.NoSuchUserException: if some users were not found and autocreate is False. """ # Skip any addresses that look like "--" or are empty, # because that means "no user". # Also, make sure all email addresses are lower case. needed_emails = [ email.lower() for email in emails if email and not framework_constants.NO_VALUE_RE.match(email) ] # Look up these users in the RAM cache user_id_dict = self.LookupExistingUserIDs(cnxn, needed_emails) if len(needed_emails) == len(user_id_dict): logging.info('found all %d emails', len(user_id_dict)) return user_id_dict # If any were not found in the DB, create them or raise an exception. nonexist_emails = [ email for email in needed_emails if email not in user_id_dict ] logging.info('nonexist_emails: %r, autocreate is %r', nonexist_emails, autocreate) if not autocreate: raise exceptions.NoSuchUserException('%r' % nonexist_emails) if not allowgroups: # Only create accounts for valid email addresses. nonexist_emails = [ email for email in nonexist_emails if validate.IsValidEmail(email) ] if not nonexist_emails: return user_id_dict self._CreateUsers(cnxn, nonexist_emails) created_rows = self.user_tbl.Select(cnxn, cols=['email', 'user_id'], email=nonexist_emails) created_dict = dict(created_rows) # Cache all the user IDs that we retrieved to make later requests faster. self.user_id_cache.CacheAll(created_dict) user_id_dict.update(created_dict) logging.info('looked up User IDs %r', user_id_dict) return user_id_dict
def _ParseOneRule(cnxn, predicate, action_type, action_value, user_service, rule_num, error_list): """Parse one FilterRule based on the action type.""" if action_type == 'default_status': status = framework_bizobj.CanonicalizeLabel(action_value) rule = MakeRule(predicate, default_status=status) elif action_type == 'default_owner': if action_value: try: user_id = user_service.LookupUserID(cnxn, action_value) except user_svc.NoSuchUserException: user_id = framework_constants.NO_USER_SPECIFIED error_list.append('Rule %d: No such user: %s' % (rule_num, action_value)) else: user_id = framework_constants.NO_USER_SPECIFIED rule = MakeRule(predicate, default_owner_id=user_id) elif action_type == 'add_ccs': cc_ids = [] for email in re.split('[,;\s]+', action_value): if not email.strip(): continue try: user_id = user_service.LookupUserID(cnxn, email.strip(), autocreate=True) cc_ids.append(user_id) except user_svc.NoSuchUserException: error_list.append('Rule %d: No such user: %s' % (rule_num, email.strip())) rule = MakeRule(predicate, add_cc_ids=cc_ids) elif action_type == 'add_labels': add_labels = framework_constants.IDENTIFIER_RE.findall(action_value) rule = MakeRule(predicate, add_labels=add_labels) elif action_type == 'also_notify': add_notify = [] for addr in re.split('[,;\s]+', action_value): if validate.IsValidEmail(addr.strip()): add_notify.append(addr.strip()) else: error_list.append('Rule %d: Invalid email address: %s' % (rule_num, addr.strip())) rule = MakeRule(predicate, add_notify=add_notify) else: logging.info('unexpected action type, probably tampering:%r', action_type) raise monorailrequest.InputException() return rule
def Linkify(_mr, autolink_regex_match, _component_ref_artifacts): """Examine a textual reference and replace it with a hyperlink or not. This is a callback for use with the autolink feature. The function parameters are standard for this type of callback. Args: _mr: unused information parsed from the HTTP request. autolink_regex_match: regex match for the textual reference. _component_ref_artifacts: unused result of call to GetReferencedIssues. Returns: A list of TextRuns with tag=a for all matched ftp, http, https and mailto links converted into HTML hyperlinks. """ hyperlink = autolink_regex_match.group(0) trailing = '' for begin, end in _LINK_TRAILING_CHARS: if hyperlink.endswith(end): if not begin or hyperlink[:-len(end)].find(begin) == -1: trailing = end + trailing hyperlink = hyperlink[:-len(end)] tag_match = _CLOSING_TAG_RE.search(hyperlink) if tag_match: trailing = hyperlink[tag_match.start(0):] + trailing hyperlink = hyperlink[:tag_match.start(0)] href = hyperlink if not href.lower().startswith(('http', 'ftp', 'mailto')): # We use http because redirects for https are not all set up. href = 'http://' + href if (not validate.IsValidURL(href) and not (href.startswith('mailto') and validate.IsValidEmail(href[7:]))): return [template_helpers.TextRun(autolink_regex_match.group(0))] result = [template_helpers.TextRun(hyperlink, tag='a', href=href)] if trailing: result.append(template_helpers.TextRun(trailing)) return result
def ProcessFormData(self, mr, post_data): """Process the posted form.""" # 1. Parse and validate user input. summary, description = self._ParseMeta(post_data, mr.errors) access = project_helpers.ParseProjectAccess(mr.project, post_data.get('access')) only_owners_remove_restrictions = ('only_owners_remove_restrictions' in post_data) only_owners_see_contributors = 'only_owners_see_contributors' in post_data issue_notify = post_data['issue_notify'] if issue_notify and not validate.IsValidEmail(issue_notify): mr.errors.issue_notify = _MSG_INVALID_EMAIL_ADDRESS process_inbound_email = 'process_inbound_email' in post_data home_page = post_data.get('project_home') if home_page and not (home_page.startswith('http:') or home_page.startswith('https:')): mr.errors.project_home = 'Home page link must start with http: or https:' docs_url = post_data.get('docs_url') if docs_url and not (docs_url.startswith('http:') or docs_url.startswith('https:')): mr.errors.docs_url = 'Documentation link must start with http: or https:' source_url = post_data.get('source_url') if source_url and not (source_url.startswith('http:') or source_url.startswith('https:')): mr.errors.source_url = 'Source link must start with http: or https:' logo_gcs_id = '' logo_file_name = '' if 'logo' in post_data and not isinstance(post_data['logo'], basestring): item = post_data['logo'] logo_file_name = item.filename try: logo_gcs_id = gcs_helpers.StoreLogoInGCS( logo_file_name, item.value, mr.project.project_id) except gcs_helpers.UnsupportedMimeType, e: mr.errors.logo = e.message
def _Linkify(autolink_regex_match, shorthand=False): """Examine a textual reference and replace it with a hyperlink or not. This is a callback for use with the autolink feature. Args: autolink_regex_match: regex match for the textual reference. shorthand: Set to True to allow shorthand links without "http". Returns: A list of TextRuns with tag=a for all matched ftp, http, https and mailto links converted into HTML hyperlinks. """ hyperlink = autolink_regex_match.group(0) trailing = '' for begin, end in _LINK_TRAILING_CHARS: if hyperlink.endswith(end): if not begin or hyperlink[:-len(end)].find(begin) == -1: trailing = end + trailing hyperlink = hyperlink[:-len(end)] tag_match = _CLOSING_TAG_RE.search(hyperlink) if tag_match: trailing = hyperlink[tag_match.start(0):] + trailing hyperlink = hyperlink[:tag_match.start(0)] href = hyperlink if shorthand and not href.lower().startswith('http'): # We use http because redirects for https are not all set up. href = 'http://' + href if (not validate.IsValidURL(href) and not validate.IsValidEmail(href)): return [template_helpers.TextRun(autolink_regex_match.group(0))] result = [template_helpers.TextRun(hyperlink, tag='a', href=href)] if trailing: result.append(template_helpers.TextRun(trailing)) return result
def IngestUserRefs(cnxn, user_refs, user_service, autocreate=False): """Return IDs of specified users or raise NoSuchUserException.""" # Filter out user_refs with invalid display_names. # Invalid emails won't get auto-created in LookupUserIds, but un-specified # user_ref.user_id values have the zero-value 0. So invalid user_ref's # need to be filtered out here to prevent these resulting in '0's in # the 'result' array. if autocreate: user_refs = [ user_ref for user_ref in user_refs if (not user_ref.display_name) or validate.IsValidEmail(user_ref.display_name) ] # 1. Verify that all specified user IDs actually match existing users. user_ids_to_verify = [ user_ref.user_id for user_ref in user_refs if user_ref.user_id ] user_service.LookupUserEmails(cnxn, user_ids_to_verify) # 2. Lookup or create any users that are specified by email address. needed_emails = [ user_ref.display_name for user_ref in user_refs if not user_ref.user_id and user_ref.display_name ] emails_to_ids = user_service.LookupUserIDs(cnxn, needed_emails, autocreate=autocreate) # 3. Build the result from emails_to_ids or straight from user_ref's # user_id. # Note: user_id can be specified as 0 to clear the issue owner. result = [ emails_to_ids.get(user_ref.display_name, user_ref.user_id) for user_ref in user_refs ] return result