blob: 17dead840125f342cd144755da6e3c948f9495a9 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed 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."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import logging
12import time
13
14import ezt
15
16from framework import framework_bizobj
17from framework import framework_constants
18from framework import framework_helpers
19from framework import permissions
20from framework import template_helpers
21from framework import timestr
22from proto import user_pb2
23from services import client_config_svc
24import settings
25
26
27_LABEL_DISPLAY_CHARS = 30
28_LABEL_PART_DISPLAY_CHARS = 15
29
30
31class LabelView(object):
32 """Wrapper class that makes it easier to display a label via EZT."""
33
34 def __init__(self, label, config):
35 """Make several values related to this label available as attrs.
36
37 Args:
38 label: artifact label string. E.g., 'Priority-High' or 'Frontend'.
39 config: PB with a well_known_labels list, or None.
40 """
41 self.name = label
42 self.is_restrict = ezt.boolean(permissions.IsRestrictLabel(label))
43
44 self.docstring = ''
45 if config:
46 for wkl in config.well_known_labels:
47 if label.lower() == wkl.label.lower():
48 self.docstring = wkl.label_docstring
49
50 if '-' in label:
51 self.prefix, self.value = label.split('-', 1)
52 else:
53 self.prefix, self.value = '', label
54
55
56class StatusView(object):
57 """Wrapper class that makes it easier to display a status via EZT."""
58
59 def __init__(self, status, config):
60 """Make several values related to this status available as attrs.
61
62 Args:
63 status: artifact status string. E.g., 'New' or 'Accepted'.
64 config: PB with a well_known_statuses list, or None.
65 """
66
67 self.name = status
68
69 self.docstring = ''
70 self.means_open = ezt.boolean(True)
71 if config:
72 for wks in config.well_known_statuses:
73 if status.lower() == wks.status.lower():
74 self.docstring = wks.status_docstring
75 self.means_open = ezt.boolean(wks.means_open)
76
77
78class UserView(object):
79 """Wrapper class to easily display basic user information in a template."""
80
81 def __init__(self, user, is_group=False):
82 self.user = user
83 self.is_group = is_group
84 email = user.email or ''
85 self.user_id = user.user_id
86 self.email = email
87 if user.obscure_email:
88 self.profile_url = '/u/%s/' % user.user_id
89 else:
90 self.profile_url = '/u/%s/' % email
91 self.obscure_email = user.obscure_email
92 self.banned = ''
93
94 (self.username, self.domain, self.obscured_username,
95 obscured_email) = framework_bizobj.ParseAndObscureAddress(email)
96 # No need to obfuscate or reveal client email.
97 # Instead display a human-readable username.
98 if self.user_id == framework_constants.DELETED_USER_ID:
99 self.display_name = framework_constants.DELETED_USER_NAME
100 self.obscure_email = ''
101 self.profile_url = ''
102 elif self.email in client_config_svc.GetServiceAccountMap():
103 self.display_name = client_config_svc.GetServiceAccountMap()[self.email]
104 elif not self.obscure_email:
105 self.display_name = email
106 else:
107 self.display_name = obscured_email
108
109 self.avail_message, self.avail_state = (
110 framework_helpers.GetUserAvailability(user, is_group))
111 self.avail_message_short = template_helpers.FitUnsafeText(
112 self.avail_message, 35)
113
114 def RevealEmail(self):
115 if not self.email:
116 return
117 if self.email not in client_config_svc.GetServiceAccountMap():
118 self.obscure_email = False
119 self.display_name = self.email
120 self.profile_url = '/u/%s/' % self.email
121
122
123def MakeAllUserViews(
124 cnxn, user_service, *list_of_user_id_lists, **kw):
125 """Make a dict {user_id: user_view, ...} for all user IDs given."""
126 distinct_user_ids = set()
127 distinct_user_ids.update(*list_of_user_id_lists)
128 if None in distinct_user_ids:
129 distinct_user_ids.remove(None)
130 group_ids = kw.get('group_ids', [])
131 user_dict = user_service.GetUsersByIDs(cnxn, distinct_user_ids)
132 return {user_id: UserView(user_pb, is_group=user_id in group_ids)
133 for user_id, user_pb in user_dict.items()}
134
135
136def MakeUserView(cnxn, user_service, user_id):
137 """Make a UserView for the given user ID."""
138 user = user_service.GetUser(cnxn, user_id)
139 return UserView(user)
140
141
142def StuffUserView(user_id, email, obscure_email):
143 """Construct a UserView with the given parameters for testing."""
144 user = user_pb2.MakeUser(user_id, email=email, obscure_email=obscure_email)
145 return UserView(user)
146
147
148# TODO(https://crbug.com/monorail/8192): Remove optional project.
149def RevealAllEmailsToMembers(cnxn, services, auth, users_by_id, project=None):
150 # type: (MonorailConnection, Services, AuthData, Collection[user_pb2.User],
151 # Optional[project_pb2.Project] -> None)
152 """Reveal emails based on the authenticated user.
153
154 The actual behavior can be determined by looking into
155 framework_bizobj.ShouldRevealEmail. Look at https://crbug.com/monorail/8030
156 for context.
157 This method should be deleted when endpoints and ezt pages are deprecated.
158
159 Args:
160 cnxn: MonorailConnection to the database.
161 services: Services object for connections to backend services.
162 auth: AuthData object that identifies the logged in user.
163 users_by_id: dictionary of UserView's that might be displayed.
164 project: Optional Project PB for the current project.
165
166 Returns:
167 Nothing, but the UserViews in users_by_id may be modified to
168 publish email address.
169 """
170 if project:
171 for user_view in users_by_id.values():
172 if framework_bizobj.DeprecatedShouldRevealEmail(auth, project,
173 user_view.email):
174 user_view.RevealEmail()
175 else:
176 viewable_users = framework_bizobj.FilterViewableEmails(
177 cnxn, services, auth, users_by_id.values())
178 for user_view in viewable_users:
179 user_view.RevealEmail()
180
181
182def RevealAllEmails(users_by_id):
183 """Allow anyone to see unobscured email addresses of project members.
184
185 The modified view objects should only be used to generate views for other
186 project members.
187
188 Args:
189 users_by_id: dictionary of UserViews 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.values():
196 user_view.RevealEmail()
197
198
199def GetViewedUserDisplayName(mr):
200 """Get display name of the viewed user given the logged-in user."""
201 # Do not obscure email if current user is a site admin. Do not obscure
202 # email if current user is viewing their own profile. For all other
203 # cases do whatever obscure_email setting for the user is.
204 viewing_self = mr.auth.user_id == mr.viewed_user_auth.user_id
205 email_obscured = (not(mr.auth.user_pb.is_site_admin or viewing_self)
206 and mr.viewed_user_auth.user_view.obscure_email)
207 if email_obscured:
208 (_username, _domain, _obscured_username,
209 obscured_email) = framework_bizobj.ParseAndObscureAddress(
210 mr.viewed_user_auth.email)
211 viewed_user_display_name = obscured_email
212 else:
213 viewed_user_display_name = mr.viewed_user_auth.email
214
215 return viewed_user_display_name