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 testProcessException(self): """Expected exceptions are converted to pRPC codes, expected not.""" self.CheckExceptionStatus( exceptions.NoSuchUserException(), codes.StatusCode.NOT_FOUND) self.CheckExceptionStatus( exceptions.NoSuchProjectException(), codes.StatusCode.NOT_FOUND) self.CheckExceptionStatus( exceptions.NoSuchIssueException(), codes.StatusCode.NOT_FOUND) self.CheckExceptionStatus( exceptions.NoSuchComponentException(), codes.StatusCode.NOT_FOUND) self.CheckExceptionStatus( permissions.BannedUserException(), codes.StatusCode.PERMISSION_DENIED) self.CheckExceptionStatus( permissions.PermissionException(), codes.StatusCode.PERMISSION_DENIED) self.CheckExceptionStatus( exceptions.GroupExistsException(), codes.StatusCode.INVALID_ARGUMENT) self.CheckExceptionStatus( exceptions.InvalidComponentNameException(), codes.StatusCode.INVALID_ARGUMENT) self.CheckExceptionStatus( ratelimiter.ApiRateLimitExceeded('client_id', 'email'), codes.StatusCode.PERMISSION_DENIED) self.CheckExceptionStatus( features_svc.HotlistAlreadyExists(), codes.StatusCode.INVALID_ARGUMENT) self.CheckExceptionStatus(NotImplementedError(), None)
def UpdateUser(self, cnxn, user_id, user): """Store a user PB in the database. Args: cnxn: connection to SQL database. user_id: int user ID of the user to update. user: User PB to store. Returns: Nothing. """ if not user_id: raise exceptions.NoSuchUserException( 'Cannot update anonymous user') delta = { 'is_site_admin': user.is_site_admin, 'notify_issue_change': user.notify_issue_change, 'notify_starred_issue_change': user.notify_starred_issue_change, 'email_compact_subject': user.email_compact_subject, 'email_view_widget': user.email_view_widget, 'notify_starred_ping': user.notify_starred_ping, 'banned': user.banned, 'after_issue_update': str(user.after_issue_update or 'UP_TO_LIST'), 'keep_people_perms_open': user.keep_people_perms_open, 'preview_on_hover': user.preview_on_hover, 'obscure_email': user.obscure_email, 'last_visit_timestamp': user.last_visit_timestamp, 'email_bounce_timestamp': user.email_bounce_timestamp, 'vacation_message': user.vacation_message, } # Start sending UPDATE statements, but don't COMMIT until the end. self.user_tbl.Update(cnxn, delta, user_id=user_id, commit=False) # Rewrite all the DismissedCues rows. cues_rows = [(user_id, cue) for cue in user.dismissed_cues] self.dismissedcues_tbl.Delete(cnxn, user_id=user_id, commit=False) self.dismissedcues_tbl.InsertRows(cnxn, DISMISSEDCUES_COLS, cues_rows, commit=False) cnxn.Commit() self.user_2lc.InvalidateKeys(cnxn, [user_id])
def LookupUserEmails(self, cnxn, user_ids, ignore_missed=False): """Return a dict of email addresses for the given user IDs. Args: cnxn: connection to SQL database. user_ids: list of int user IDs to look up. ignore_missed: if True, does not throw NoSuchUserException, when there are users not found for some user_ids. Returns: A dict {user_id: email_addr} for all the requested IDs. Raises: exceptions.NoSuchUserException: if any requested user cannot be found and ignore_missed is False. """ self.email_cache.CacheItem(framework_constants.NO_USER_SPECIFIED, '') emails_dict, missed_ids = self.email_cache.GetAll(user_ids) if missed_ids: logging.info('got %d user emails from cache', len(emails_dict)) rows = self.user_tbl.Select(cnxn, cols=['user_id', 'email'], user_id=missed_ids) retrieved_dict = dict(rows) logging.info('looked up users %r', retrieved_dict) self.email_cache.CacheAll(retrieved_dict) emails_dict.update(retrieved_dict) # Check if there are any that we could not find. ID 0 means "no user". nonexist_ids = [ user_id for user_id in user_ids if user_id and user_id not in emails_dict ] if nonexist_ids: if ignore_missed: logging.info('No email addresses found for users %r' % nonexist_ids) else: raise exceptions.NoSuchUserException( 'No email addresses found for users %r' % nonexist_ids) return emails_dict
def LookupUserID(self, cnxn, email, autocreate=False, allowgroups=False): """Get one user ID for the given email address. Args: cnxn: connection to SQL database. email: string email address of the user to look up. 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: The int user ID of the specified user. Raises: exceptions.NoSuchUserException if the user was not found and autocreate is False. """ email = email.lower() email_dict = self.LookupUserIDs(cnxn, [email], autocreate=autocreate, allowgroups=allowgroups) if email not in email_dict: raise exceptions.NoSuchUserException('%r not found' % email) return email_dict[email]
def IngestFieldValues(cnxn, user_service, field_values, config, phases=None): """Ingest a list of protoc FieldValues and create protorpc FieldValues. Args: cnxn: connection to the DB. user_service: interface to user data storage. field_values: a list of protoc FieldValue used by the API. config: ProjectIssueConfig for this field_value's project. phases: a list of the issue's protorpc Phases. Returns: A protorpc FieldValue object. """ fds_by_name = {fd.field_name.lower(): fd for fd in config.field_defs} phases_by_name = {phase.name: phase.phase_id for phase in phases or []} ingested_fvs = [] for fv in field_values: fd = fds_by_name.get(fv.field_ref.field_name.lower()) if fd: if not fv.value: logging.info('Ignoring blank field value: %r', fv) continue ingested_fv = field_helpers.ParseOneFieldValue( cnxn, user_service, fd, fv.value) if not ingested_fv: raise exceptions.InputException( 'Unparsable value for field %s' % fv.field_ref.field_name) if ingested_fv.user_id == field_helpers.INVALID_USER_ID: raise exceptions.NoSuchUserException() if fd.is_phase_field: ingested_fv.phase_id = phases_by_name.get( fv.phase_ref.phase_name) ingested_fvs.append(ingested_fv) return ingested_fvs