Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/framework/framework_views.py b/framework/framework_views.py
new file mode 100644
index 0000000..17dead8
--- /dev/null
+++ b/framework/framework_views.py
@@ -0,0 +1,215 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+"""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 proto 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