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