OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """View classes to make it easy to display framework objects in EZT.""" |
| 7 |
| 8 from third_party import ezt |
| 9 |
| 10 from framework import framework_bizobj |
| 11 from framework import framework_constants |
| 12 from framework import permissions |
| 13 from framework import template_helpers |
| 14 from services import client_config_svc |
| 15 import settings |
| 16 |
| 17 |
| 18 _LABEL_DISPLAY_CHARS = 30 |
| 19 _LABEL_PART_DISPLAY_CHARS = 15 |
| 20 |
| 21 |
| 22 class LabelView(object): |
| 23 """Wrapper class that makes it easier to display a label via EZT.""" |
| 24 |
| 25 def __init__(self, label, config): |
| 26 """Make several values related to this label available as attrs. |
| 27 |
| 28 Args: |
| 29 label: artifact label string. E.g., 'Priority-High' or 'Frontend'. |
| 30 config: PB with a well_known_labels list, or None. |
| 31 """ |
| 32 self.name = label |
| 33 self.tooltip = label |
| 34 self.is_restrict = ezt.boolean(permissions.IsRestrictLabel(label)) |
| 35 |
| 36 self.docstring = '' |
| 37 if config: |
| 38 for wkl in config.well_known_labels: |
| 39 if label.lower() == wkl.label.lower(): |
| 40 self.docstring = wkl.label_docstring |
| 41 |
| 42 if '-' in label: |
| 43 self.prefix, self.value = label.split('-', 1) |
| 44 else: |
| 45 self.prefix, self.value = '', label |
| 46 |
| 47 |
| 48 class StatusView(object): |
| 49 """Wrapper class that makes it easier to display a status via EZT.""" |
| 50 |
| 51 def __init__(self, status, config): |
| 52 """Make several values related to this status available as attrs. |
| 53 |
| 54 Args: |
| 55 status: artifact status string. E.g., 'New' or 'Accepted'. |
| 56 config: PB with a well_known_statuses list, or None. |
| 57 """ |
| 58 |
| 59 self.name = status |
| 60 self.tooltip = status |
| 61 |
| 62 self.docstring = '' |
| 63 self.means_open = ezt.boolean(True) |
| 64 if config: |
| 65 for wks in config.well_known_statuses: |
| 66 if status.lower() == wks.status.lower(): |
| 67 self.docstring = wks.status_docstring |
| 68 self.means_open = ezt.boolean(wks.means_open) |
| 69 |
| 70 |
| 71 class UserView(object): |
| 72 """Wrapper class to easily display basic user information in a template.""" |
| 73 |
| 74 def __init__(self, user_id, email, obscure_email): |
| 75 email = email or '' |
| 76 self.user_id = user_id |
| 77 self.email = email |
| 78 self.profile_url = '/u/%s/' % user_id |
| 79 self.obscure_email = obscure_email |
| 80 self.banned = '' |
| 81 |
| 82 (self.username, self.domain, |
| 83 self.obscured_username) = ParseAndObscureAddress(email) |
| 84 # No need to obfuscate or reveal client email. |
| 85 # Instead display a human-readable username. |
| 86 if not self.email: |
| 87 self.display_name = 'a deleted user' |
| 88 self.obscure_email = '' |
| 89 self.profile_url = '' |
| 90 elif self.email in client_config_svc.GetServiceAccountMap(): |
| 91 self.display_name = client_config_svc.GetServiceAccountMap()[self.email] |
| 92 elif not self.obscure_email: |
| 93 self.display_name = email |
| 94 else: |
| 95 self.display_name = '%s...@%s' % (self.obscured_username, self.domain) |
| 96 |
| 97 def RevealEmail(self): |
| 98 if not self.email: |
| 99 return |
| 100 if self.email not in client_config_svc.GetServiceAccountMap(): |
| 101 self.obscure_email = False |
| 102 self.display_name = self.email |
| 103 self.profile_url = '/u/%s/' % self.email |
| 104 |
| 105 |
| 106 def MakeAllUserViews(cnxn, user_service, *list_of_user_id_lists): |
| 107 """Make a dict {user_id: user_view, ...} for all user IDs given.""" |
| 108 distinct_user_ids = set() |
| 109 distinct_user_ids.update(*list_of_user_id_lists) |
| 110 user_dict = user_service.GetUsersByIDs(cnxn, distinct_user_ids) |
| 111 return {user_id: UserView(user_id, user_pb.email, user_pb.obscure_email) |
| 112 for user_id, user_pb in user_dict.iteritems()} |
| 113 |
| 114 |
| 115 def MakeUserView(cnxn, user_service, user_id): |
| 116 """Make a UserView for the given user ID.""" |
| 117 user = user_service.GetUser(cnxn, user_id) |
| 118 return UserView(user_id, user.email, user.obscure_email) |
| 119 |
| 120 |
| 121 def ParseAndObscureAddress(email): |
| 122 """Break the given email into username and domain, and obscure. |
| 123 |
| 124 Args: |
| 125 email: string email address to process |
| 126 |
| 127 Returns: |
| 128 A 3-tuple (username, domain, obscured_username). |
| 129 The obscured_username is trucated the same way that Google Groups does it. |
| 130 """ |
| 131 if '@' in email: |
| 132 username, user_domain = email.split('@', 1) |
| 133 else: # don't fail if User table has unexpected email address format. |
| 134 username, user_domain = email, '' |
| 135 |
| 136 base_username = username.split('+')[0] |
| 137 cutoff_point = min(8, max(1, len(base_username) - 3)) |
| 138 obscured_username = base_username[:cutoff_point] |
| 139 |
| 140 return username, user_domain, obscured_username |
| 141 |
| 142 |
| 143 def _ShouldRevealEmail(auth, project, viewed_email): |
| 144 """Decide whether to publish a user's email address. |
| 145 |
| 146 Args: |
| 147 auth: The AuthData of the user viewing the email addresses. |
| 148 project: The project to which the viewed users belong. |
| 149 viewed_email: The email of the viewed user. |
| 150 |
| 151 Returns: |
| 152 True if email addresses should be published to the logged-in user. |
| 153 """ |
| 154 # Case 1: Anon users don't see anything revealed. |
| 155 if auth.user_pb is None: |
| 156 return False |
| 157 |
| 158 # Case 2: site admins always see unobscured email addresses. |
| 159 if auth.user_pb.is_site_admin: |
| 160 return True |
| 161 |
| 162 # Case 3: Domain users in same-org-only projects always see unobscured addrs. |
| 163 # TODO(jrobbins): re-implement same_org |
| 164 |
| 165 # Case 4: Project members see the unobscured email of everyone in a project. |
| 166 if project and framework_bizobj.UserIsInProject(project, auth.effective_ids): |
| 167 return True |
| 168 |
| 169 # Case 5: Emails that end in priviledged user domains see unobscured email |
| 170 # addresses. |
| 171 if framework_bizobj.IsPriviledgedDomainUser(auth.user_pb.email): |
| 172 return True |
| 173 |
| 174 # Case 6: Do not obscure your own email. |
| 175 if viewed_email and auth.user_pb.email == viewed_email: |
| 176 return True |
| 177 |
| 178 return False |
| 179 |
| 180 |
| 181 def RevealAllEmailsToMembers(mr, users_by_id): |
| 182 """Allow project members to see unobscured email addresses in that project. |
| 183 |
| 184 Non project member addresses will be obscured. |
| 185 Site admins can see all email addresses unobscured. |
| 186 |
| 187 Args: |
| 188 mr: common info parsed from the user's request. |
| 189 users_by_id: dictionary of UserView's that will be displayed. |
| 190 |
| 191 Returns: |
| 192 Nothing, but the UserViews in users_by_id may be modified to |
| 193 publish email address. |
| 194 """ |
| 195 for user_view in users_by_id.itervalues(): |
| 196 if _ShouldRevealEmail(mr.auth, mr.project, user_view.email): |
| 197 user_view.RevealEmail() |
| 198 |
| 199 |
| 200 def RevealAllEmails(users_by_id): |
| 201 """Allow anyone to see unobscured email addresses of project members. |
| 202 |
| 203 The modified view objects should only be used to generate views for other |
| 204 project members. |
| 205 |
| 206 Args: |
| 207 users_by_id: dictionary of UserViews that will be displayed. |
| 208 |
| 209 Returns: |
| 210 Nothing, but the UserViews in users_by_id may be modified to |
| 211 publish email address. |
| 212 """ |
| 213 for user_view in users_by_id.itervalues(): |
| 214 user_view.RevealEmail() |
OLD | NEW |