Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(395)

Side by Side Diff: appengine/monorail/tracker/issueexport.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/monorail/tracker/issueentry.py ('k') | appengine/monorail/tracker/issueimport.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 """Servlet to export a range of issues in JSON format.
7 """
8
9 import logging
10 import time
11
12 from third_party import ezt
13
14 from framework import permissions
15 from framework import jsonfeed
16 from framework import servlet
17 from tracker import tracker_bizobj
18
19
20 class IssueExport(servlet.Servlet):
21 """IssueExportControls let's an admin choose how to export issues."""
22
23 _PAGE_TEMPLATE = 'tracker/issue-export-page.ezt'
24 _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_ISSUES
25
26 def AssertBasePermission(self, mr):
27 """Make sure that the logged in user has permission to view this page."""
28 super(IssueExport, self).AssertBasePermission(mr)
29 if not mr.auth.user_pb.is_site_admin:
30 raise permissions.PermissionException(
31 'Only site admins may export issues')
32
33 def GatherPageData(self, mr):
34 """Build up a dictionary of data values to use when rendering the page."""
35
36 return {
37 'issue_tab_mode': None,
38 'initial_start': mr.start,
39 'initial_num': mr.num,
40 'page_perms': self.MakePagePerms(mr, None, permissions.CREATE_ISSUE),
41 }
42
43
44 class IssueExportJSON(jsonfeed.JsonFeed):
45 """IssueExport shows a range of issues in JSON format."""
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(IssueExportJSON, self).AssertBasePermission(mr)
53 if not mr.auth.user_pb.is_site_admin:
54 raise permissions.PermissionException(
55 'Only site admins may export issues')
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 if not mr.start and not mr.num:
67 issues = self.services.issue.GetAllIssuesInProject(
68 mr.cnxn, mr.project.project_id)
69 else:
70 local_id_range = range(mr.start, mr.start + mr.num)
71 issues = self.services.issue.GetIssuesByLocalIDs(
72 mr.cnxn, mr.project.project_id, local_id_range)
73 user_id_set = tracker_bizobj.UsersInvolvedInIssues(issues)
74
75 comments_dict = self.services.issue.GetCommentsForIssues(
76 mr.cnxn, [issue.issue_id for issue in issues])
77 for comment_list in comments_dict.itervalues():
78 user_id_set.update(
79 tracker_bizobj.UsersInvolvedInCommentList(comment_list))
80
81 starrers_dict = self.services.issue_star.LookupItemsStarrers(
82 mr.cnxn, [issue.issue_id for issue in issues])
83 for starrer_id_list in starrers_dict.itervalues():
84 user_id_set.update(starrer_id_list)
85
86 # The value 0 indicates "no user", e.g., that an issue has no owner.
87 # We don't need to create a User row to represent that.
88 user_id_set.discard(0)
89 email_dict = self.services.user.LookupUserEmails(mr.cnxn, user_id_set)
90
91 issues_json = [
92 self._MakeIssueJSON(
93 mr, issue, email_dict,
94 comments_dict.get(issue.issue_id, []),
95 starrers_dict.get(issue.issue_id, []))
96 for issue in issues if not issue.deleted]
97
98 json_data = {
99 'metadata': {
100 'version': 1,
101 'when': int(time.time()),
102 'who': mr.auth.email,
103 'project': mr.project_name,
104 'start': mr.start,
105 'num': mr.num,
106 },
107 'issues': issues_json,
108 # This list could be derived from the 'issues', but we provide it for
109 # ease of processing.
110 'emails': email_dict.values(),
111 }
112 return json_data
113
114 def _MakeAmendmentJSON(self, amendment, email_dict):
115 amendment_json = {
116 'field': amendment.field.name,
117 }
118 if amendment.custom_field_name:
119 amendment_json.update({'custom_field_name': amendment.custom_field_name})
120 if amendment.newvalue:
121 amendment_json.update({'new_value': amendment.newvalue})
122 if amendment.added_user_ids:
123 amendment_json.update(
124 {'added_emails': [email_dict.get(user_id)
125 for user_id in amendment.added_user_ids]})
126 if amendment.removed_user_ids:
127 amendment_json.update(
128 {'removed_emails': [email_dict.get(user_id)
129 for user_id in amendment.removed_user_ids]})
130 return amendment_json
131
132 def _MakeAttachmentJSON(self, attachment):
133 if attachment.deleted:
134 return None
135 attachment_json = {
136 'name': attachment.filename,
137 'size': attachment.filesize,
138 'mimetype': attachment.mimetype,
139 'gcs_object_id': attachment.gcs_object_id,
140 }
141 return attachment_json
142
143 def _MakeCommentJSON(self, comment, email_dict):
144 if comment.deleted_by:
145 return None
146 amendments = [self._MakeAmendmentJSON(a, email_dict)
147 for a in comment.amendments]
148 attachments = [self._MakeAttachmentJSON(a)
149 for a in comment.attachments]
150 comment_json = {
151 'timestamp': comment.timestamp,
152 'commenter': email_dict.get(comment.user_id),
153 'content': comment.content,
154 'amendments': [a for a in amendments if a],
155 'attachments': [a for a in attachments if a],
156 }
157 return comment_json
158
159 def _MakeFieldValueJSON(self, mr, field, email_dict):
160 field_value_json = {
161 'field': self.services.config.LookupField(
162 mr.cnxn, mr.project.project_id, field.field_id)
163 }
164 if field.int_value:
165 field_value_json['int_value'] = field.int_value
166 if field.str_value:
167 field_value_json['str_value'] = field.str_value
168 if field.user_id:
169 field_value_json['user_value'] = email_dict.get(field.user_id)
170 return field_value_json
171
172 def _MakeIssueJSON(
173 self, mr, issue, email_dict, comment_list, starrer_id_list):
174 """Return a dict of info about the issue and its comments."""
175 comments = [self._MakeCommentJSON(c, email_dict) for c in comment_list]
176 issue_json = {
177 'local_id': issue.local_id,
178 'reporter': email_dict.get(issue.reporter_id),
179 'summary': issue.summary,
180 'owner': email_dict.get(issue.owner_id),
181 'status': issue.status,
182 'cc': [email_dict[cc_id] for cc_id in issue.cc_ids],
183 'labels': issue.labels,
184 'fields': [self._MakeFieldValueJSON(mr, field, email_dict)
185 for field in issue.field_values],
186 'starrers': [email_dict[starrer] for starrer in starrer_id_list],
187 'comments': [c for c in comments if c],
188 'opened': issue.opened_timestamp,
189 'modified': issue.modified_timestamp,
190 'closed': issue.closed_timestamp,
191 }
192 # TODO(agable): Export cross-project references as well.
193 if issue.blocked_on_iids:
194 issue_json['blocked_on'] = [i.local_id for i in
195 self.services.issue.GetIssues(mr.cnxn, issue.blocked_on_iids)
196 if i.project_id == mr.project.project_id]
197 if issue.blocking_iids:
198 issue_json['blocking'] = [i.local_id for i in
199 self.services.issue.GetIssues(mr.cnxn, issue.blocking_iids)
200 if i.project_id == mr.project.project_id]
201 if issue.merged_into:
202 merge = self.services.issue.GetIssue(mr.cnxn, issue.merged_into)
203 if merge.project_id == mr.project.project_id:
204 issue_json['merged_into'] = merge.local_id
205 return issue_json
OLDNEW
« no previous file with comments | « appengine/monorail/tracker/issueentry.py ('k') | appengine/monorail/tracker/issueimport.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698