blob: c97cf79810f87ed68bd31b91b7eefbbe1ceefa40 [file] [log] [blame]
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is govered by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
"""JSON feed for issue presubmit warnings."""
import logging
from businesslogic import work_env
from features import filterrules_helpers
from framework import framework_views
from framework import jsonfeed
from framework import permissions
from proto import tracker_pb2
from tracker import field_helpers
from tracker import tracker_bizobj
from tracker import tracker_helpers
from services import issue_svc
class IssuePresubmitJSON(jsonfeed.JsonFeed):
"""JSON data for any warnings as the user edits an issue."""
def AssertBasePermission(self, mr):
"""Make sure that the logged in user has permission to view this page."""
super(IssuePresubmitJSON, self).AssertBasePermission(mr)
if mr.local_id is None:
return # For issue creation, there is no existing issue.
with work_env.WorkEnv(mr, self.services) as we:
issue = we.GetIssueByLocalID(mr.project_id, mr.local_id)
config = we.GetProjectConfig(mr.project_id)
granted_perms = tracker_bizobj.GetGrantedPerms(
issue, mr.auth.effective_ids, config)
permit_view = permissions.CanViewIssue(
mr.auth.effective_ids, mr.perms, mr.project, issue,
granted_perms=granted_perms)
if not permit_view:
logging.warning('Issue is %r', issue)
raise permissions.PermissionException(
'User is not allowed to view this issue')
def HandleRequest(self, mr):
"""Provide the UI with warning info as the user edits an issue.
Args:
mr: common information parsed from the HTTP request.
Returns:
Results dictionary in JSON format.
"""
existing_issue = None
if mr.local_id:
with work_env.WorkEnv(mr, self.services) as we:
existing_issue = we.GetIssueByLocalID(mr.project_id, mr.local_id)
with mr.profiler.Phase('parsing request'):
post_data = mr.request.POST
parsed = tracker_helpers.ParseIssueRequest(
mr.cnxn, post_data, self.services, mr.errors, mr.project_name)
logging.info('parsed.users %r', parsed.users)
with mr.profiler.Phase('making user views'):
involved_user_ids = [parsed.users.owner_id]
users_by_id = framework_views.MakeAllUserViews(
mr.cnxn, self.services.user, involved_user_ids)
proposed_owner_view = users_by_id[parsed.users.owner_id]
with work_env.WorkEnv(mr, self.services) as we:
config = we.GetProjectConfig(mr.project_id)
component_ids = tracker_helpers.LookupComponentIDs(
parsed.components.paths, config, mr.errors)
with mr.profiler.Phase('initializing proposed_issue'):
proposed_issue = self.MakeProposedIssue(
mr, existing_issue, parsed, config, component_ids)
with mr.profiler.Phase('applying rules'):
_any_change, traces = filterrules_helpers.ApplyFilterRules(
mr.cnxn, self.services, proposed_issue, config)
logging.info('proposed_issue is now: %r', proposed_issue)
logging.info('traces are: %r', traces)
with mr.profiler.Phase('making derived user views'):
derived_users_by_id = framework_views.MakeAllUserViews(
mr.cnxn, self.services.user, [proposed_issue.derived_owner_id],
proposed_issue.derived_cc_ids)
with mr.profiler.Phase('pair derived values with rule explanations'):
(derived_labels_and_why, derived_owner_and_why,
derived_cc_and_why, warnings_and_why, errors_and_why
) = PairDerivedValuesWithRuleExplanations(
proposed_issue, traces, derived_users_by_id)
return {
'owner_availability': proposed_owner_view.avail_message_short,
'owner_avail_state': proposed_owner_view.avail_state,
'derived_labels': derived_labels_and_why,
'derived_owner_email': derived_owner_and_why,
'derived_cc_emails': derived_cc_and_why,
'warnings': warnings_and_why,
'errors': errors_and_why,
}
def MakeProposedIssue(
self, mr, existing_issue, parsed, config, component_ids):
"""Create an Issue in RAM as input to the filter rules."""
field_helpers.ShiftEnumFieldsIntoLabels(
parsed.labels, parsed.labels_remove,
parsed.fields.vals, parsed.fields.vals_remove, config)
field_values = field_helpers.ParseFieldValues(
mr.cnxn, self.services.user, parsed.fields.vals, config)
proposed_issue = tracker_pb2.Issue(
project_id=mr.project_id, local_id=mr.local_id,
summary=parsed.summary, status=parsed.status,
owner_id=parsed.users.owner_id, labels=parsed.labels,
component_ids=component_ids, project_name=mr.project_name,
field_values=field_values)
if existing_issue:
proposed_issue.attachment_count = existing_issue.attachment_count
proposed_issue.star_count = existing_issue.star_count
return proposed_issue
def PairDerivedValuesWithRuleExplanations(
proposed_issue, traces, derived_users_by_id):
"""Pair up values and explanations into JSON objects."""
derived_labels_and_why = [
{'value': lab,
'why': traces.get((tracker_pb2.FieldID.LABELS, lab))}
for lab in proposed_issue.derived_labels]
derived_owner_and_why = []
if proposed_issue.derived_owner_id:
derived_owner_and_why = [{
'value': derived_users_by_id[proposed_issue.derived_owner_id].email,
'why': traces.get(
(tracker_pb2.FieldID.OWNER, proposed_issue.derived_owner_id)),
}]
derived_cc_and_why = [
{'value': derived_users_by_id[cc_id].email,
'why': traces.get((tracker_pb2.FieldID.CC, cc_id))}
for cc_id in proposed_issue.derived_cc_ids
if cc_id in derived_users_by_id and derived_users_by_id[cc_id].email]
warnings_and_why = [
{'value': warning,
'why': traces.get((tracker_pb2.FieldID.WARNING, warning))}
for warning in proposed_issue.derived_warnings]
errors_and_why = [
{'value': error,
'why': traces.get((tracker_pb2.FieldID.ERROR, error))}
for error in proposed_issue.derived_errors]
return (derived_labels_and_why, derived_owner_and_why, derived_cc_and_why,
warnings_and_why, errors_and_why)