1# Copyright 2015 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4"""Provides the web interface for filing a bug on the issue tracker.""" 5from __future__ import print_function 6from __future__ import division 7from __future__ import absolute_import 8 9from google.appengine.api import users 10from google.appengine.ext import ndb 11 12from dashboard import oauth2_decorator 13from dashboard.common import file_bug 14from dashboard.common import request_handler 15from dashboard.common import utils 16 17 18class FileBugHandler(request_handler.RequestHandler): 19 """Uses oauth2 to file a new bug with a set of alerts.""" 20 21 def post(self): 22 """A POST request for this endpoint is the same as a GET request.""" 23 self.get() 24 25 @oauth2_decorator.DECORATOR.oauth_required 26 def get(self): 27 """Either shows the form to file a bug, or if filled in, files the bug. 28 29 The form to file a bug is popped up from the triage-dialog polymer element. 30 The default summary, description and label strings are constructed there. 31 32 Request parameters: 33 summary: Bug summary string. 34 description: Bug full description string. 35 keys: Comma-separated Alert keys in urlsafe format. 36 finish: Boolean set to true when creating a bug, false otherwise. 37 project_id: The Monorail project ID (used to create a bug). 38 labels: Bug labels (used to create a bug). 39 components: Bug components (used to create a bug). 40 owner: Bug owner email address (used to create a bug). 41 cc: Bug emails to CC (used to create a bug). 42 43 Outputs: 44 HTML, using the template 'bug_result.html'. 45 """ 46 if not utils.IsValidSheriffUser(): 47 self.RenderHtml( 48 'bug_result.html', { 49 'error': 'You must be logged in with a chromium.org account ' 50 'to file bugs.' 51 }) 52 return 53 54 summary = self.request.get('summary') 55 description = self.request.get('description') 56 keys = self.request.get('keys') 57 58 if not keys: 59 self.RenderHtml('bug_result.html', 60 {'error': 'No alerts specified to add bugs to.'}) 61 return 62 63 if self.request.get('finish'): 64 project_id = self.request.get('project_id', 'chromium') 65 labels = self.request.get_all('label') 66 components = self.request.get_all('component') 67 owner = self.request.get('owner') 68 cc = self.request.get('cc') 69 self._CreateBug(owner, cc, summary, description, project_id, labels, 70 components, keys) 71 else: 72 self._ShowBugDialog(summary, description, keys) 73 74 def _ShowBugDialog(self, summary, description, urlsafe_keys): 75 """Sends a HTML page with a form for filing the bug. 76 77 Args: 78 summary: The default bug summary string. 79 description: The default bug description string. 80 urlsafe_keys: Comma-separated Alert keys in urlsafe format. 81 """ 82 alert_keys = [ndb.Key(urlsafe=k) for k in urlsafe_keys.split(',')] 83 labels, components = file_bug.FetchLabelsAndComponents(alert_keys) 84 owner_components = file_bug.FetchBugComponents(alert_keys) 85 self.RenderHtml( 86 'bug_result.html', { 87 'bug_create_form': True, 88 'keys': urlsafe_keys, 89 'summary': summary, 90 'description': description, 91 'projects': utils.MONORAIL_PROJECTS, 92 'labels': labels, 93 'components': components.union(owner_components), 94 'owner': '', 95 'cc': users.get_current_user(), 96 }) 97 98 def _CreateBug(self, owner, cc, summary, description, project_id, labels, 99 components, urlsafe_keys): 100 """Creates a bug, associates it with the alerts, sends a HTML response. 101 102 Args: 103 owner: The owner of the bug, must end with @{project_id}.org or 104 @google.com if not empty. 105 cc: CSV of email addresses to CC on the bug. 106 summary: The new bug summary string. 107 description: The new bug description string. 108 project_id: The Monorail project ID used to create the bug. 109 labels: List of label strings for the new bug. 110 components: List of component strings for the new bug. 111 urlsafe_keys: Comma-separated alert keys in urlsafe format. 112 """ 113 # Only project members (@{project_id}.org or @google.com accounts) 114 # can be owners of bugs. 115 project_domain = '@%s.org' % project_id 116 if owner and not owner.endswith(project_domain) and not owner.endswith( 117 '@google.com'): 118 self.RenderHtml( 119 'bug_result.html', { 120 'error': 121 'Owner email address must end with %s or @google.com.' % 122 project_domain 123 }) 124 return 125 126 http = oauth2_decorator.DECORATOR.http() 127 template_params = file_bug.FileBug(http, owner, cc, summary, description, 128 project_id, labels, components, 129 urlsafe_keys.split(',')) 130 self.RenderHtml('bug_result.html', template_params) 131