| # Copyright 2016 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """View classes to make it easy to display framework objects in EZT.""" |
| from __future__ import print_function |
| from __future__ import division |
| from __future__ import absolute_import |
| |
| import logging |
| import time |
| |
| import ezt |
| |
| from framework import framework_bizobj |
| from framework import framework_constants |
| from framework import framework_helpers |
| from framework import permissions |
| from framework import template_helpers |
| from framework import timestr |
| from mrproto import user_pb2 |
| from services import client_config_svc |
| import settings |
| |
| |
| _LABEL_DISPLAY_CHARS = 30 |
| _LABEL_PART_DISPLAY_CHARS = 15 |
| |
| |
| class LabelView(object): |
| """Wrapper class that makes it easier to display a label via EZT.""" |
| |
| def __init__(self, label, config): |
| """Make several values related to this label available as attrs. |
| |
| Args: |
| label: artifact label string. E.g., 'Priority-High' or 'Frontend'. |
| config: PB with a well_known_labels list, or None. |
| """ |
| self.name = label |
| self.is_restrict = ezt.boolean(permissions.IsRestrictLabel(label)) |
| |
| self.docstring = '' |
| if config: |
| for wkl in config.well_known_labels: |
| if label.lower() == wkl.label.lower(): |
| self.docstring = wkl.label_docstring |
| |
| if '-' in label: |
| self.prefix, self.value = label.split('-', 1) |
| else: |
| self.prefix, self.value = '', label |
| |
| |
| class StatusView(object): |
| """Wrapper class that makes it easier to display a status via EZT.""" |
| |
| def __init__(self, status, config): |
| """Make several values related to this status available as attrs. |
| |
| Args: |
| status: artifact status string. E.g., 'New' or 'Accepted'. |
| config: PB with a well_known_statuses list, or None. |
| """ |
| |
| self.name = status |
| |
| self.docstring = '' |
| self.means_open = ezt.boolean(True) |
| if config: |
| for wks in config.well_known_statuses: |
| if status.lower() == wks.status.lower(): |
| self.docstring = wks.status_docstring |
| self.means_open = ezt.boolean(wks.means_open) |
| |
| |
| class UserView(object): |
| """Wrapper class to easily display basic user information in a template.""" |
| |
| def __init__(self, user, is_group=False): |
| self.user = user |
| self.is_group = is_group |
| email = user.email or '' |
| self.user_id = user.user_id |
| self.email = email |
| if user.obscure_email: |
| self.profile_url = '/u/%s/' % user.user_id |
| else: |
| self.profile_url = '/u/%s/' % email |
| self.obscure_email = user.obscure_email |
| self.banned = '' |
| |
| (self.username, self.domain, self.obscured_username, |
| obscured_email) = framework_bizobj.ParseAndObscureAddress(email) |
| # No need to obfuscate or reveal client email. |
| # Instead display a human-readable username. |
| if self.user_id == framework_constants.DELETED_USER_ID: |
| self.display_name = framework_constants.DELETED_USER_NAME |
| self.obscure_email = '' |
| self.profile_url = '' |
| elif self.email in client_config_svc.GetServiceAccountMap(): |
| self.display_name = client_config_svc.GetServiceAccountMap()[self.email] |
| elif not self.obscure_email: |
| self.display_name = email |
| else: |
| self.display_name = obscured_email |
| |
| self.avail_message, self.avail_state = ( |
| framework_helpers.GetUserAvailability(user, is_group)) |
| self.avail_message_short = template_helpers.FitUnsafeText( |
| self.avail_message, 35) |
| |
| def RevealEmail(self): |
| if not self.email: |
| return |
| if self.email not in client_config_svc.GetServiceAccountMap(): |
| self.obscure_email = False |
| self.display_name = self.email |
| self.profile_url = '/u/%s/' % self.email |
| |
| |
| def MakeAllUserViews( |
| cnxn, user_service, *list_of_user_id_lists, **kw): |
| """Make a dict {user_id: user_view, ...} for all user IDs given.""" |
| distinct_user_ids = set() |
| distinct_user_ids.update(*list_of_user_id_lists) |
| if None in distinct_user_ids: |
| distinct_user_ids.remove(None) |
| group_ids = kw.get('group_ids', []) |
| user_dict = user_service.GetUsersByIDs(cnxn, distinct_user_ids) |
| return {user_id: UserView(user_pb, is_group=user_id in group_ids) |
| for user_id, user_pb in user_dict.items()} |
| |
| |
| def MakeUserView(cnxn, user_service, user_id): |
| """Make a UserView for the given user ID.""" |
| user = user_service.GetUser(cnxn, user_id) |
| return UserView(user) |
| |
| |
| def StuffUserView(user_id, email, obscure_email): |
| """Construct a UserView with the given parameters for testing.""" |
| user = user_pb2.MakeUser(user_id, email=email, obscure_email=obscure_email) |
| return UserView(user) |
| |
| |
| # TODO(https://crbug.com/monorail/8192): Remove optional project. |
| def RevealAllEmailsToMembers(cnxn, services, auth, users_by_id, project=None): |
| # type: (MonorailConnection, Services, AuthData, Collection[user_pb2.User], |
| # Optional[project_pb2.Project] -> None) |
| """Reveal emails based on the authenticated user. |
| |
| The actual behavior can be determined by looking into |
| framework_bizobj.ShouldRevealEmail. Look at https://crbug.com/monorail/8030 |
| for context. |
| This method should be deleted when endpoints and ezt pages are deprecated. |
| |
| Args: |
| cnxn: MonorailConnection to the database. |
| services: Services object for connections to backend services. |
| auth: AuthData object that identifies the logged in user. |
| users_by_id: dictionary of UserView's that might be displayed. |
| project: Optional Project PB for the current project. |
| |
| Returns: |
| Nothing, but the UserViews in users_by_id may be modified to |
| publish email address. |
| """ |
| if project: |
| for user_view in users_by_id.values(): |
| if framework_bizobj.DeprecatedShouldRevealEmail(auth, project, |
| user_view.email): |
| user_view.RevealEmail() |
| else: |
| viewable_users = framework_bizobj.FilterViewableEmails( |
| cnxn, services, auth, users_by_id.values()) |
| for user_view in viewable_users: |
| user_view.RevealEmail() |
| |
| |
| def RevealAllEmails(users_by_id): |
| """Allow anyone to see unobscured email addresses of project members. |
| |
| The modified view objects should only be used to generate views for other |
| project members. |
| |
| Args: |
| users_by_id: dictionary of UserViews that will be displayed. |
| |
| Returns: |
| Nothing, but the UserViews in users_by_id may be modified to |
| publish email address. |
| """ |
| for user_view in users_by_id.values(): |
| user_view.RevealEmail() |
| |
| |
| def GetViewedUserDisplayName(mr): |
| """Get display name of the viewed user given the logged-in user.""" |
| # Do not obscure email if current user is a site admin. Do not obscure |
| # email if current user is viewing their own profile. For all other |
| # cases do whatever obscure_email setting for the user is. |
| viewing_self = mr.auth.user_id == mr.viewed_user_auth.user_id |
| email_obscured = (not(mr.auth.user_pb.is_site_admin or viewing_self) |
| and mr.viewed_user_auth.user_view.obscure_email) |
| if email_obscured: |
| (_username, _domain, _obscured_username, |
| obscured_email) = framework_bizobj.ParseAndObscureAddress( |
| mr.viewed_user_auth.email) |
| viewed_user_display_name = obscured_email |
| else: |
| viewed_user_display_name = mr.viewed_user_auth.email |
| |
| return viewed_user_display_name |