blob: cc9353c5efda63d00664fe322b621eaf2d2269e4 [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"""Servlet to export a project's config in JSON format.
6"""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
Copybara854996b2021-09-07 19:36:02 +000011import time
12
Copybara854996b2021-09-07 19:36:02 +000013from framework import permissions
14from framework import jsonfeed
15from framework import servlet
16from project import project_helpers
Copybara854996b2021-09-07 19:36:02 +000017
18
19class ProjectExport(servlet.Servlet):
20 """Only site admins can export a project"""
21
22 _PAGE_TEMPLATE = 'project/project-export-page.ezt'
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010023 _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_ADMIN
Copybara854996b2021-09-07 19:36:02 +000024
25 def AssertBasePermission(self, mr):
26 """Make sure that the logged in user has permission to view this page."""
27 super(ProjectExport, self).AssertBasePermission(mr)
28 if not mr.auth.user_pb.is_site_admin:
29 raise permissions.PermissionException(
30 'Only site admins may export project configuration')
31
32 def GatherPageData(self, mr):
33 """Build up a dictionary of data values to use when rendering the page."""
34
35 return {
36 'admin_tab_mode': None,
37 'page_perms': self.MakePagePerms(mr, None, permissions.CREATE_ISSUE),
38 }
39
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010040 def GetProjectExportPage(self, **kwargs):
41 return self.handler(**kwargs)
Copybara854996b2021-09-07 19:36:02 +000042
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +020043
Copybara854996b2021-09-07 19:36:02 +000044class ProjectExportJSON(jsonfeed.JsonFeed):
45 """ProjectExportJSON shows all configuration for a Project in JSON form."""
46
47 # Pretty-print the JSON output.
48 JSON_INDENT = 4
49
50 def AssertBasePermission(self, mr):
51 """Make sure that the logged in user has permission to view this page."""
52 super(ProjectExportJSON, self).AssertBasePermission(mr)
53 if not mr.auth.user_pb.is_site_admin:
54 raise permissions.PermissionException(
55 'Only site admins may export project configuration')
56
57 def HandleRequest(self, mr):
58 """Build up a dictionary of data values to use when rendering the page.
59
60 Args:
61 mr: commonly used info parsed from the request.
62
63 Returns:
64 Dict of values used by EZT for rendering the page.
65 """
66 project = self.services.project.GetProject(mr.cnxn, mr.project.project_id)
67 user_id_set = project_helpers.UsersInvolvedInProject(project)
68
69 config = self.services.config.GetProjectConfig(
70 mr.cnxn, mr.project.project_id)
71 templates = self.services.template.GetProjectTemplates(
72 mr.cnxn, config.project_id)
73 involved_users = self.services.config.UsersInvolvedInConfig(
74 config, templates)
75 user_id_set.update(involved_users)
76
77 # The value 0 indicates "no user", e.g., that an issue has no owner.
78 # We don't need to create a User row to represent that.
79 user_id_set.discard(0)
80 email_dict = self.services.user.LookupUserEmails(mr.cnxn, user_id_set)
81
82 project_json = self._MakeProjectJSON(project, email_dict)
83 config_json = self._MakeConfigJSON(config, email_dict, templates)
84
85 json_data = {
86 'metadata': {
87 'version': 1,
88 'when': int(time.time()),
89 'who': mr.auth.email,
90 },
91 'project': project_json,
92 'config': config_json,
93 # This list could be derived from the others, but we provide it for
94 # ease of processing.
95 'emails': list(email_dict.values()),
96 }
97 return json_data
98
99 def _MakeProjectJSON(self, project, email_dict):
100 project_json = {
101 'name': project.project_name,
102 'summary': project.summary,
103 'description': project.description,
104 'state': project.state.name,
105 'access': project.access.name,
106 'owners': [email_dict.get(user) for user in project.owner_ids],
107 'committers': [email_dict.get(user) for user in project.committer_ids],
108 'contributors': [
109 email_dict.get(user) for user in project.contributor_ids],
110 'perms': [self._MakePermJSON(perm, email_dict)
111 for perm in project.extra_perms],
112 'issue_notify_address': project.issue_notify_address,
113 'attachment_bytes': project.attachment_bytes_used,
114 'attachment_quota': project.attachment_quota,
115 'recent_activity': project.recent_activity,
116 'process_inbound_email': project.process_inbound_email,
117 'only_owners_remove_restrictions':
118 project.only_owners_remove_restrictions,
119 'only_owners_see_contributors': project.only_owners_see_contributors,
120 'revision_url_format': project.revision_url_format,
121 'read_only_reason': project.read_only_reason,
122 }
123 return project_json
124
125 def _MakePermJSON(self, perm, email_dict):
126 perm_json = {
127 'member': email_dict.get(perm.member_id),
128 'perms': [p for p in perm.perms],
129 }
130 return perm_json
131
132 def _MakeConfigJSON(self, config, email_dict, project_templates):
133 config_json = {
134 'statuses':
135 [self._MakeStatusJSON(status)
136 for status in config.well_known_statuses],
137 'statuses_offer_merge':
138 [status for status in config.statuses_offer_merge],
139 'labels':
140 [self._MakeLabelJSON(label) for label in config.well_known_labels],
141 'exclusive_label_prefixes':
142 [label for label in config.exclusive_label_prefixes],
143 # TODO(http://crbug.com/monorail/7217): Export the project's FieldDefs.
144 'components':
145 [self._MakeComponentJSON(component, email_dict)
146 for component in config.component_defs],
147 'templates':
148 [self._MakeTemplateJSON(template, email_dict)
149 for template in project_templates],
150 'developer_template': config.default_template_for_developers,
151 'user_template': config.default_template_for_users,
152 'list_cols': config.default_col_spec,
153 'list_spec': config.default_sort_spec,
154 'grid_x': config.default_x_attr,
155 'grid_y': config.default_y_attr,
156 'only_known_values': config.restrict_to_known,
157 }
158 if config.custom_issue_entry_url:
159 config_json.update({'issue_entry_url': config.custom_issue_entry_url})
160 return config_json
161
162 def _MakeTemplateJSON(self, template, email_dict):
163 template_json = {
164 'name': template.name,
165 'summary': template.summary,
166 'content': template.content,
167 'summary_must_be_edited': template.summary_must_be_edited,
168 'owner': email_dict.get(template.owner_id),
169 'status': template.status,
170 'labels': [label for label in template.labels],
171 # TODO(http://crbug.com/monorail/7217): Export the template's Fields.
172 'members_only': template.members_only,
173 'owner_defaults_to_member': template.owner_defaults_to_member,
174 'component_required': template.component_required,
175 'admins': [email_dict(user) for user in template.admin_ids],
176 }
177 return template_json
178
179 def _MakeStatusJSON(self, status):
180 status_json = {
181 'status': status.status,
182 'open': status.means_open,
183 'docstring': status.status_docstring,
184 }
185 return status_json
186
187 def _MakeLabelJSON(self, label):
188 label_json = {
189 'label': label.label,
190 'docstring': label.label_docstring,
191 }
192 return label_json
193
194 def _MakeComponentJSON(self, component, email_dict):
195 component_json = {
196 'path': component.path,
197 'docstring': component.docstring,
198 'admins': [email_dict.get(user) for user in component.admin_ids],
199 'ccs': [email_dict.get(user) for user in component.cc_ids],
200 }
201 return component_json
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +0200202
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100203 def GetProjectExportJSONPage(self, **kwargs):
204 return self.handler(**kwargs)
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +0200205
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100206 def PostProjectExportJSONPage(self, **kwargs):
207 return self.handler(**kwargs)