Beispiel #1
0
    def _CalculateIssuePings(self, issue, config):
        """Return a list of (field, timestamp) pairs for dates that should ping."""
        timestamp_min, timestamp_max = _GetTimestampRange(int(time.time()))
        arrived_dates_by_field_id = {
            fv.field_id: fv.date_value
            for fv in issue.field_values
            if timestamp_min <= fv.date_value < timestamp_max
        }
        logging.info('arrived_dates_by_field_id = %r',
                     arrived_dates_by_field_id)
        # TODO(jrobbins): Lookup field defs regardless of project_id to better
        # handle foreign fields in issues that have been moved between projects.
        pings = [(field, arrived_dates_by_field_id[field.field_id])
                 for field in config.field_defs
                 if (field.field_id in arrived_dates_by_field_id and field.
                     date_action in (tracker_pb2.DateAction.PING_OWNER_ONLY,
                                     tracker_pb2.DateAction.PING_PARTICIPANTS))
                 ]

        # TODO(jrobbins): For now, assume all pings apply only to open issues.
        # Later, allow each date action to specify whether it applies to open
        # issues or all issues.
        means_open = tracker_helpers.MeansOpenInProject(
            tracker_bizobj.GetStatus(issue), config)
        pings = [ping for ping in pings if means_open]

        pings = sorted(pings, key=lambda ping: ping[0].field_name)
        return pings
Beispiel #2
0
def ConvertStatusRef(explicit_status, derived_status, config):
    """Use the given status strings to create a StatusRef."""
    status = explicit_status or derived_status
    is_derived = not explicit_status
    if not status:
        return common_pb2.StatusRef(status=framework_constants.NO_VALUES,
                                    is_derived=False,
                                    means_open=True)

    return common_pb2.StatusRef(status=status,
                                is_derived=is_derived,
                                means_open=tracker_helpers.MeansOpenInProject(
                                    status, config))
Beispiel #3
0
    def testGetStatusWithoutOwner(self, status, means_open, expected_status):
        """Tests GetStatus without an owner."""
        self.test_msg.replace_header(AlertEmailHeader.STATUS, status)
        self.mox.StubOutWithMock(tracker_helpers, 'MeansOpenInProject')
        tracker_helpers.MeansOpenInProject(
            status, mox.IgnoreArg()).AndReturn(means_open)

        self.mox.ReplayAll()
        props = alert2issue.GetAlertProperties(self.services, self.cnxn,
                                               self.project_id,
                                               self.incident_id,
                                               self.trooper_queue,
                                               self.test_msg)
        self.assertCaseInsensitiveEqual(props['status'], expected_status)
        self.mox.VerifyAll()
Beispiel #4
0
def StatusDefsAsText(config):
    """Return two strings for editing open and closed status definitions."""
    open_lines = []
    closed_lines = []
    for wks in config.well_known_statuses:
        line = '%s%s%s%s' % ('#' if wks.deprecated else '', wks.status.ljust(
            20), '\t= ' if wks.status_docstring else '', wks.status_docstring)

        if tracker_helpers.MeansOpenInProject(wks.status, config):
            open_lines.append(line)
        else:
            closed_lines.append(line)

    open_text = '\n'.join(open_lines)
    closed_text = '\n'.join(closed_lines)
    logging.info('open_text is \n%s', open_text)
    logging.info('closed_text is \n%s', closed_text)
    return open_text, closed_text
Beispiel #5
0
def _make_issue_view(default_pn, config, viewable_iids_set, ref_issue):
    viewable = ref_issue.issue_id in viewable_iids_set
    return {
        "id":
        tracker_bizobj.FormatIssueRef(
            (ref_issue.project_name, ref_issue.local_id),
            default_project_name=default_pn),
        "href":
        tracker_helpers.FormatRelativeIssueURL(ref_issue.project_name,
                                               urls.ISSUE_DETAIL,
                                               id=ref_issue.local_id),
        "closed":
        ezt.boolean(
            viewable and
            not tracker_helpers.MeansOpenInProject(ref_issue.status, config)),
        "title":
        ref_issue.summary if viewable else ""
    }
Beispiel #6
0
def _GetStatus(proj_config, owner_id, status):
    # XXX: what if assigned and available are not in known_statuses?
    if status:
        status = status.strip().lower()
    if owner_id:
        # If there is an owner, the status must be 'Assigned'.
        if status and status != 'assigned':
            logging.info(
                'invalid status %s for an alert with an owner; default to assigned',
                status)
        return 'assigned'

    if status:
        if tracker_helpers.MeansOpenInProject(status, proj_config):
            return status
        logging.info('invalid status %s for an alert; default to available',
                     status)

    return 'available'
Beispiel #7
0
  def __init__(self, mr, services, config):
    """Gather data for the issue section of a project admin page.

    Args:
      mr: MonorailRequest, including a database connection, the current
          project, and authenticated user IDs.
      services: Persist services with ProjectService, ConfigService, and
          UserService included.
      config: ProjectIssueConfig for the current project..

    Returns:
      Project info in a dict suitable for EZT.
    """
    super(ConfigView, self).__init__(config)
    self.open_statuses = []
    self.closed_statuses = []
    for wks in config.well_known_statuses:
      item = template_helpers.EZTItem(
          name=wks.status,
          name_padded=wks.status.ljust(20),
          commented='#' if wks.deprecated else '',
          docstring=wks.status_docstring)
      if tracker_helpers.MeansOpenInProject(wks.status, config):
        self.open_statuses.append(item)
      else:
        self.closed_statuses.append(item)

    self.templates = [
        IssueTemplateView(mr, tmpl, services.user, config)
        for tmpl in config.templates]
    for index, template in enumerate(self.templates):
      template.index = index

    self.field_names = [  # TODO(jrobbins): field-level controls
        fd.field_name for fd in config.field_defs if not fd.is_deleted]
    self.issue_labels = tracker_helpers.LabelsNotMaskedByFields(
        config, self.field_names)
    self.excl_prefixes = [
        prefix.lower() for prefix in config.exclusive_label_prefixes]
    self.restrict_to_known = ezt.boolean(config.restrict_to_known)

    self.default_col_spec = (
        config.default_col_spec or tracker_constants.DEFAULT_COL_SPEC)
Beispiel #8
0
    def __init__(self,
                 mr,
                 services,
                 config,
                 template=None,
                 load_all_templates=False):
        """Gather data for the issue section of a project admin page.

    Args:
      mr: MonorailRequest, including a database connection, the current
          project, and authenticated user IDs.
      services: Persist services with ProjectService, ConfigService,
          TemplateService and UserService included.
      config: ProjectIssueConfig for the current project..
      template (TemplateDef, optional): the current template.
      load_all_templates (boolean): default False. If true loads self.templates.

    Returns:
      Project info in a dict suitable for EZT.
    """
        super(ConfigView, self).__init__(config)
        self.open_statuses = []
        self.closed_statuses = []
        for wks in config.well_known_statuses:
            item = template_helpers.EZTItem(
                name=wks.status,
                name_padded=wks.status.ljust(20),
                commented='#' if wks.deprecated else '',
                docstring=wks.status_docstring)
            if tracker_helpers.MeansOpenInProject(wks.status, config):
                self.open_statuses.append(item)
            else:
                self.closed_statuses.append(item)

        is_member = framework_bizobj.UserIsInProject(mr.project,
                                                     mr.auth.effective_ids)
        template_set = services.template.GetTemplateSetForProject(
            mr.cnxn, config.project_id)

        # Filter non-viewable templates
        self.template_names = []
        for _, template_name, members_only in template_set:
            if members_only and not is_member:
                continue
            self.template_names.append(template_name)

        if load_all_templates:
            templates = services.template.GetProjectTemplates(
                mr.cnxn, config.project_id)
            self.templates = [
                IssueTemplateView(mr, tmpl, services.user, config)
                for tmpl in templates
            ]
            for index, template_view in enumerate(self.templates):
                template_view.index = index

        if template:
            self.template_view = IssueTemplateView(mr, template, services.user,
                                                   config)

        self.field_names = [  # TODO(jrobbins): field-level controls
            fd.field_name for fd in config.field_defs
            if fd.field_type is tracker_pb2.FieldTypes.ENUM_TYPE
            and not fd.is_deleted
        ]
        self.issue_labels = tracker_helpers.LabelsNotMaskedByFields(
            config, self.field_names)
        self.excl_prefixes = [
            prefix.lower() for prefix in config.exclusive_label_prefixes
        ]
        self.restrict_to_known = ezt.boolean(config.restrict_to_known)

        self.default_col_spec = (config.default_col_spec
                                 or tracker_constants.DEFAULT_COL_SPEC)
Beispiel #9
0
    def __init__(self, issue, users_by_id, config):
        """Store relevant values for later display by EZT.

    Args:
      issue: An Issue protocol buffer.
      users_by_id: dict {user_id: UserViews} for all users mentioned in issue.
      config: ProjectIssueConfig for this issue.
    """
        super(IssueView, self).__init__(issue)

        # The users involved in this issue must be present in users_by_id if
        # this IssueView is to be used on the issue detail or peek pages. But,
        # they can be absent from users_by_id if the IssueView is used as a
        # tile in the grid view.
        self.owner = users_by_id.get(issue.owner_id)
        self.derived_owner = users_by_id.get(issue.derived_owner_id)
        self.cc = [users_by_id.get(cc_id) for cc_id in issue.cc_ids if cc_id]
        self.derived_cc = [
            users_by_id.get(cc_id) for cc_id in issue.derived_cc_ids if cc_id
        ]
        self.status = framework_views.StatusView(issue.status, config)
        self.derived_status = framework_views.StatusView(
            issue.derived_status, config)
        # If we don't have a config available, we don't need to access is_open, so
        # let it be True.
        self.is_open = ezt.boolean(
            not config or tracker_helpers.MeansOpenInProject(
                tracker_bizobj.GetStatus(issue), config))

        self.components = sorted([
            ComponentValueView(component_id, config, False)
            for component_id in issue.component_ids
            if tracker_bizobj.FindComponentDefByID(component_id, config)
        ] + [
            ComponentValueView(component_id, config, True)
            for component_id in issue.derived_component_ids
            if tracker_bizobj.FindComponentDefByID(component_id, config)
        ],
                                 key=lambda cvv: cvv.path)

        self.fields = MakeAllFieldValueViews(config, issue.labels,
                                             issue.derived_labels,
                                             issue.field_values, users_by_id)

        labels, derived_labels = tracker_bizobj.ExplicitAndDerivedNonMaskedLabels(
            issue, config)
        self.labels = [
            framework_views.LabelView(label, config) for label in labels
        ]
        self.derived_labels = [
            framework_views.LabelView(label, config)
            for label in derived_labels
        ]
        self.restrictions = _RestrictionsView(issue)

        # TODO(jrobbins): sort by order of labels in project config

        self.short_summary = issue.summary[:tracker_constants.
                                           SHORT_SUMMARY_LENGTH]

        if issue.closed_timestamp:
            self.closed = timestr.FormatAbsoluteDate(issue.closed_timestamp)
        else:
            self.closed = ''

        self.blocked_on = []
        self.has_dangling = ezt.boolean(self.dangling_blocked_on_refs)
        self.blocking = []

        self.detail_relative_url = tracker_helpers.FormatRelativeIssueURL(
            issue.project_name, urls.ISSUE_DETAIL, id=issue.local_id)
        self.crbug_url = tracker_helpers.FormatCrBugURL(
            issue.project_name, issue.local_id)
Beispiel #10
0
def convert_issue(cls, issue, mar, services):
    """Convert Monorail Issue PB to API IssuesGetInsertResponse."""

    config = services.config.GetProjectConfig(mar.cnxn, issue.project_id)
    granted_perms = tracker_bizobj.GetGrantedPerms(issue,
                                                   mar.auth.effective_ids,
                                                   config)
    issue_project = services.project.GetProject(mar.cnxn, issue.project_id)
    component_list = []
    for cd in config.component_defs:
        cid = cd.component_id
        if cid in issue.component_ids:
            component_list.append(cd.path)
    cc_list = [convert_person(p, mar.cnxn, services) for p in issue.cc_ids]
    cc_list = [p for p in cc_list if p is not None]
    field_values_list = []
    fds_by_id = {fd.field_id: fd for fd in config.field_defs}
    phases_by_id = {phase.phase_id: phase for phase in issue.phases}
    for fv in issue.field_values:
        fd = fds_by_id.get(fv.field_id)
        if not fd:
            logging.warning('Custom field %d of project %s does not exist',
                            fv.field_id, issue_project.project_name)
            continue
        val = None
        if fv.user_id:
            val = _get_user_email(services.user, mar.cnxn, fv.user_id)
        else:
            val = tracker_bizobj.GetFieldValue(fv, {})
            if not isinstance(val, string_types):
                val = str(val)
        new_fv = api_pb2_v1.FieldValue(fieldName=fd.field_name,
                                       fieldValue=val,
                                       derived=fv.derived)
        if fd.approval_id:  # Attach parent approval name
            approval_fd = fds_by_id.get(fd.approval_id)
            if not approval_fd:
                logging.warning(
                    'Parent approval field %d of field %s does not exist',
                    fd.approval_id, fd.field_name)
            else:
                new_fv.approvalName = approval_fd.field_name
        elif fv.phase_id:  # Attach phase name
            phase = phases_by_id.get(fv.phase_id)
            if not phase:
                logging.warning('Phase %d for field %s does not exist',
                                fv.phase_id, fd.field_name)
            else:
                new_fv.phaseName = phase.name
        field_values_list.append(new_fv)
    approval_values_list = convert_approvals(mar.cnxn, issue.approval_values,
                                             services, config, issue.phases)
    phases_list = convert_phases(issue.phases)
    with work_env.WorkEnv(mar, services) as we:
        starred = we.IsIssueStarred(issue)
    resp = cls(
        kind='monorail#issue',
        id=issue.local_id,
        title=issue.summary,
        summary=issue.summary,
        projectId=issue_project.project_name,
        stars=issue.star_count,
        starred=starred,
        status=issue.status,
        state=(api_pb2_v1.IssueState.open
               if tracker_helpers.MeansOpenInProject(
                   tracker_bizobj.GetStatus(issue), config) else
               api_pb2_v1.IssueState.closed),
        labels=issue.labels,
        components=component_list,
        author=convert_person(issue.reporter_id, mar.cnxn, services),
        owner=convert_person(issue.owner_id, mar.cnxn, services),
        cc=cc_list,
        updated=datetime.datetime.fromtimestamp(issue.modified_timestamp),
        published=datetime.datetime.fromtimestamp(issue.opened_timestamp),
        blockedOn=convert_issue_ids(issue.blocked_on_iids, mar, services),
        blocking=convert_issue_ids(issue.blocking_iids, mar, services),
        canComment=permissions.CanCommentIssue(mar.auth.effective_ids,
                                               mar.perms,
                                               issue_project,
                                               issue,
                                               granted_perms=granted_perms),
        canEdit=permissions.CanEditIssue(mar.auth.effective_ids,
                                         mar.perms,
                                         issue_project,
                                         issue,
                                         granted_perms=granted_perms),
        fieldValues=field_values_list,
        approvalValues=approval_values_list,
        phases=phases_list)
    if issue.closed_timestamp > 0:
        resp.closed = datetime.datetime.fromtimestamp(issue.closed_timestamp)
    if issue.merged_into:
        resp.mergedInto = convert_issue_ids([issue.merged_into], mar,
                                            services)[0]
    if issue.owner_modified_timestamp:
        resp.owner_modified = datetime.datetime.fromtimestamp(
            issue.owner_modified_timestamp)
    if issue.status_modified_timestamp:
        resp.status_modified = datetime.datetime.fromtimestamp(
            issue.status_modified_timestamp)
    if issue.component_modified_timestamp:
        resp.component_modified = datetime.datetime.fromtimestamp(
            issue.component_modified_timestamp)
    return resp
Beispiel #11
0
def _ApplyCond(
    cnxn, services, project, term, issue, label_set, config, owner_id, cc_ids,
    status):
  """Return True if the given issue satisfied the given predicate term."""
  op = term.op
  vals = term.str_values or term.int_values
  # Since rules are per-project, there'll be exactly 1 field
  fd = term.field_defs[0]
  field = fd.field_name

  if field == 'label':
    return _Compare(op, vals, label_set)
  if field == 'component':
    return _CompareComponents(config, op, vals, issue.component_ids)
  if field == 'any_field':
    return _Compare(op, vals, label_set) or _Compare(op, vals, [issue.summary])
  if field == 'attachments':
    return _Compare(op, term.int_values, [issue.attachment_count])
  if field == 'blocked':
    return _Compare(op, vals, issue.blocked_on_iids)
  if field == 'blockedon':
    return _CompareIssueRefs(
        cnxn, services, project, op, term.str_values, issue.blocked_on_iids)
  if field == 'blocking':
    return _CompareIssueRefs(
        cnxn, services, project, op, term.str_values, issue.blocking_iids)
  if field == 'cc':
    return _CompareUsers(cnxn, services.user, op, vals, cc_ids)
  if field == 'closed':
    return (issue.closed_timestamp and
            _Compare(op, vals, [issue.closed_timestamp]))
  if field == 'id':
    return _Compare(op, vals, [issue.local_id])
  if field == 'mergedinto':
    return _CompareIssueRefs(
        cnxn, services, project, op, term.str_values, [issue.merged_into or 0])
  if field == 'modified':
    return (issue.modified_timestamp and
            _Compare(op, vals, [issue.modified_timestamp]))
  if field == 'open':
    # TODO(jrobbins): this just checks the explicit status, not the result
    # of any previous rules.
    return tracker_helpers.MeansOpenInProject(status, config)
  if field == 'opened':
    return (issue.opened_timestamp and
            _Compare(op, vals, [issue.opened_timestamp]))
  if field == 'owner':
    return _CompareUsers(cnxn, services.user, op, vals, [owner_id])
  if field == 'reporter':
    return _CompareUsers(cnxn, services.user, op, vals, [issue.reporter_id])
  if field == 'stars':
    return _Compare(op, term.int_values, [issue.star_count])
  if field == 'status':
    return _Compare(op, vals, [status.lower()])
  if field == 'summary':
    return _Compare(op, vals, [issue.summary])

  # Since rules are per-project, it makes no sense to support field project.
  # We would need to load comments to support fields comment, commentby,
  # description, attachment.
  # Supporting starredby is probably not worth the complexity.

  logging.info('Rule with unsupported field %r was False', field)
  return False
def convert_issue(cls, issue, mar, services):
  """Convert Monorail Issue PB to API IssuesGetInsertResponse."""

  config = services.config.GetProjectConfig(mar.cnxn, issue.project_id)
  granted_perms = tracker_bizobj.GetGrantedPerms(
      issue, mar.auth.effective_ids, config)
  issue_project = services.project.GetProject(mar.cnxn, issue.project_id)
  component_list = []
  for cd in config.component_defs:
    cid = cd.component_id
    if cid in issue.component_ids:
      component_list.append(cd.path)
  cc_list = [convert_person(p, mar.cnxn, services) for p in issue.cc_ids]
  cc_list = [p for p in cc_list if p is not None]
  field_values_list = []
  field_id_dict = {
      fd.field_id: fd.field_name for fd in config.field_defs}
  for fv in issue.field_values:
    field_name = field_id_dict.get(fv.field_id)
    if not field_name:
      logging.warning('Custom field %d of project %s does not exist',
                      fv.field_id, issue_project.project_name)
      continue
    val = None
    if fv.user_id:
      val = _get_user_email(
          services.user, mar.cnxn, fv.user_id)
    elif fv.str_value:
      val = fv.str_value
    elif fv.int_value:
      val = str(fv.int_value)
    new_fv = api_pb2_v1.FieldValue(
        fieldName=field_name,
        fieldValue=val,
        derived=fv.derived)
    field_values_list.append(new_fv)
  resp = cls(
      kind='monorail#issue',
      id=issue.local_id,
      title=issue.summary,
      summary=issue.summary,
      projectId=issue_project.project_name,
      stars=issue.star_count,
      starred=services.issue_star.IsItemStarredBy(
          mar.cnxn, issue.issue_id, mar.auth.user_id),
      status=issue.status,
      state=(api_pb2_v1.IssueState.open if
             tracker_helpers.MeansOpenInProject(
                 tracker_bizobj.GetStatus(issue), config)
             else api_pb2_v1.IssueState.closed),
      labels=issue.labels,
      components=component_list,
      author=convert_person(issue.reporter_id, mar.cnxn, services),
      owner=convert_person(issue.owner_id, mar.cnxn, services),
      cc=cc_list,
      updated=datetime.datetime.fromtimestamp(issue.modified_timestamp),
      published=datetime.datetime.fromtimestamp(issue.opened_timestamp),
      blockedOn=convert_issue_ids(issue.blocked_on_iids, mar, services),
      blocking=convert_issue_ids(issue.blocking_iids, mar, services),
      canComment=permissions.CanCommentIssue(
          mar.auth.effective_ids, mar.perms, issue_project, issue,
          granted_perms=granted_perms),
      canEdit=permissions.CanEditIssue(
          mar.auth.effective_ids, mar.perms, issue_project, issue,
          granted_perms=granted_perms),
      fieldValues=field_values_list)
  if issue.closed_timestamp > 0:
    resp.closed = datetime.datetime.fromtimestamp(issue.closed_timestamp)
  if issue.merged_into:
    resp.mergedInto=convert_issue_ids([issue.merged_into], mar, services)[0]
  if issue.owner_modified_timestamp:
    resp.owner_modified = datetime.datetime.fromtimestamp(
        issue.owner_modified_timestamp)
  if issue.status_modified_timestamp:
    resp.status_modified = datetime.datetime.fromtimestamp(
        issue.status_modified_timestamp)
  if issue.component_modified_timestamp:
    resp.component_modified = datetime.datetime.fromtimestamp(
        issue.component_modified_timestamp)
  return resp
Beispiel #13
0
  def __init__(
      self, issue, users_by_id, config, open_related=None,
      closed_related=None, all_related=None):
    """Store relevant values for later display by EZT.

    Args:
      issue: An Issue protocol buffer.
      users_by_id: dict {user_id: UserViews} for all users mentioned in issue.
      config: ProjectIssueConfig for this issue.
      open_related: dict of visible open issues that are related to this issue.
      closed_related: dict {issue_id: issue} of visible closed issues that
          are related to this issue.
      all_related: dict {issue_id: issue} of all blocked-on, blocking,
          or merged-into issues referenced from this issue, regardless of
          perms.
    """
    super(IssueView, self).__init__(issue)

    # The users involved in this issue must be present in users_by_id if
    # this IssueView is to be used on the issue detail or peek pages. But,
    # they can be absent from users_by_id if the IssueView is used as a
    # tile in the grid view.
    self.owner = users_by_id.get(issue.owner_id)
    self.derived_owner = users_by_id.get(issue.derived_owner_id)
    self.cc = [users_by_id.get(cc_id) for cc_id in issue.cc_ids
               if cc_id]
    self.derived_cc = [users_by_id.get(cc_id)
                       for cc_id in issue.derived_cc_ids
                       if cc_id]
    self.status = framework_views.StatusView(issue.status, config)
    self.derived_status = framework_views.StatusView(
        issue.derived_status, config)
    # If we don't have a config available, we don't need to access is_open, so
    # let it be True.
    self.is_open = ezt.boolean(
        not config or
        tracker_helpers.MeansOpenInProject(
            tracker_bizobj.GetStatus(issue), config))

    self.components = sorted(
        [ComponentValueView(component_id, config, False)
         for component_id in issue.component_ids
         if tracker_bizobj.FindComponentDefByID(component_id, config)] +
        [ComponentValueView(component_id, config, True)
         for component_id in issue.derived_component_ids
         if tracker_bizobj.FindComponentDefByID(component_id, config)],
        key=lambda cvv: cvv.path)

    self.fields = [
        MakeFieldValueView(
            fd, config, issue.labels, issue.derived_labels, issue.field_values,
            users_by_id)
        # TODO(jrobbins): field-level view restrictions, display options
        for fd in config.field_defs
        if not fd.is_deleted]
    self.fields = sorted(
        self.fields, key=lambda f: (f.applicable_type, f.field_name))

    field_names = [fd.field_name.lower() for fd in config.field_defs
                   if not fd.is_deleted]  # TODO(jrobbins): restricts
    self.labels = [
        framework_views.LabelView(label, config)
        for label in tracker_bizobj.NonMaskedLabels(issue.labels, field_names)]
    self.derived_labels = [
        framework_views.LabelView(label, config)
        for label in issue.derived_labels
        if not tracker_bizobj.LabelIsMaskedByField(label, field_names)]
    self.restrictions = _RestrictionsView(issue)

    # TODO(jrobbins): sort by order of labels in project config

    self.short_summary = issue.summary[:tracker_constants.SHORT_SUMMARY_LENGTH]

    if issue.closed_timestamp:
      self.closed = timestr.FormatAbsoluteDate(issue.closed_timestamp)
    else:
      self.closed = ''

    blocked_on_iids = issue.blocked_on_iids
    blocking_iids = issue.blocking_iids

    # Note that merged_into_str and blocked_on_str includes all issue
    # references, even those referring to issues that the user can't view,
    # so open_related and closed_related cannot be used.
    if all_related is not None:
      all_blocked_on_refs = [
          (all_related[ref_iid].project_name, all_related[ref_iid].local_id)
          for ref_iid in issue.blocked_on_iids]
      all_blocked_on_refs.extend([
          (r.project, r.issue_id) for r in issue.dangling_blocked_on_refs])
      self.blocked_on_str = ', '.join(
          tracker_bizobj.FormatIssueRef(
              ref, default_project_name=issue.project_name)
          for ref in all_blocked_on_refs)
      all_blocking_refs = [
          (all_related[ref_iid].project_name, all_related[ref_iid].local_id)
          for ref_iid in issue.blocking_iids]
      all_blocking_refs.extend([
          (r.project, r.issue_id) for r in issue.dangling_blocking_refs])
      self.blocking_str = ', '.join(
          tracker_bizobj.FormatIssueRef(
              ref, default_project_name=issue.project_name)
          for ref in all_blocking_refs)
      if issue.merged_into:
        merged_issue = all_related[issue.merged_into]
        merged_into_ref = merged_issue.project_name, merged_issue.local_id
      else:
        merged_into_ref = None
      self.merged_into_str = tracker_bizobj.FormatIssueRef(
          merged_into_ref, default_project_name=issue.project_name)

    self.blocked_on = []
    self.has_dangling = ezt.boolean(self.dangling_blocked_on_refs)
    self.blocking = []
    current_project_name = issue.project_name

    if open_related is not None and closed_related is not None:
      self.merged_into = IssueRefView(
          current_project_name, issue.merged_into,
          open_related, closed_related)

      self.blocked_on = [
          IssueRefView(current_project_name, iid, open_related, closed_related)
          for iid in blocked_on_iids]
      self.blocked_on.extend(
          [DanglingIssueRefView(ref.project, ref.issue_id)
           for ref in issue.dangling_blocked_on_refs])
      self.blocked_on = [irv for irv in self.blocked_on if irv.visible]
      # TODO(jrobbins): sort by irv project_name and local_id

      self.blocking = [
          IssueRefView(current_project_name, iid, open_related, closed_related)
          for iid in blocking_iids]
      self.blocking.extend(
          [DanglingIssueRefView(ref.project, ref.issue_id)
           for ref in issue.dangling_blocking_refs])
      self.blocking = [irv for irv in self.blocking if irv.visible]
      # TODO(jrobbins): sort by irv project_name and local_id

    self.multiple_blocked_on = ezt.boolean(len(self.blocked_on) >= 2)
    self.detail_relative_url = tracker_helpers.FormatRelativeIssueURL(
        issue.project_name, urls.ISSUE_DETAIL, id=issue.local_id)
Beispiel #14
0
    def StoreIssueSnapshots(self, cnxn, issues, commit=True):
        """Adds an IssueSnapshot and updates the previous one for each issue."""
        for issue in issues:
            right_now = self._currentTime()

            # Look for an existing (latest) IssueSnapshot with this issue_id.
            previous_snapshots = self.issuesnapshot_tbl.Select(
                cnxn,
                cols=ISSUESNAPSHOT_COLS,
                issue_id=issue.issue_id,
                limit=1,
                order_by=[('period_start DESC', [])])

            if len(previous_snapshots) > 0:
                previous_snapshot_id = previous_snapshots[0][0]
                logging.info('Found previous IssueSnapshot with id: %s',
                             previous_snapshot_id)

                # Update previous snapshot's end time to right now.
                delta = {'period_end': right_now}
                where = [('IssueSnapshot.id = %s', [previous_snapshot_id])]
                self.issuesnapshot_tbl.Update(cnxn,
                                              delta,
                                              commit=commit,
                                              where=where)

            config = self.config_service.GetProjectConfig(
                cnxn, issue.project_id)
            period_end = settings.maximum_snapshot_period_end
            is_open = tracker_helpers.MeansOpenInProject(
                tracker_bizobj.GetStatus(issue), config)
            shard = issue.issue_id % settings.num_logical_shards
            status = tracker_bizobj.GetStatus(issue)
            status_id = self.config_service.LookupStatusID(
                cnxn, issue.project_id, status) or None
            owner_id = tracker_bizobj.GetOwnerId(issue) or None

            issuesnapshot_rows = [(issue.issue_id, shard, issue.project_id,
                                   issue.local_id, issue.reporter_id, owner_id,
                                   status_id, right_now, period_end, is_open)]

            ids = self.issuesnapshot_tbl.InsertRows(cnxn,
                                                    ISSUESNAPSHOT_COLS[1:],
                                                    issuesnapshot_rows,
                                                    replace=True,
                                                    commit=commit,
                                                    return_generated_ids=True)
            issuesnapshot_id = ids[0]

            # Add all labels to IssueSnapshot2Label.
            label_rows = [
                (issuesnapshot_id,
                 self.config_service.LookupLabelID(cnxn, issue.project_id,
                                                   label))
                for label in tracker_bizobj.GetLabels(issue)
            ]
            self.issuesnapshot2label_tbl.InsertRows(cnxn,
                                                    ISSUESNAPSHOT2LABEL_COLS,
                                                    label_rows,
                                                    replace=True,
                                                    commit=commit)

            # Add all CCs to IssueSnapshot2Cc.
            cc_rows = [(issuesnapshot_id, cc_id)
                       for cc_id in tracker_bizobj.GetCcIds(issue)]
            self.issuesnapshot2cc_tbl.InsertRows(cnxn,
                                                 ISSUESNAPSHOT2CC_COLS,
                                                 cc_rows,
                                                 replace=True,
                                                 commit=commit)

            # Add all components to IssueSnapshot2Component.
            component_rows = [(issuesnapshot_id, component_id)
                              for component_id in issue.component_ids]
            self.issuesnapshot2component_tbl.InsertRows(
                cnxn,
                ISSUESNAPSHOT2COMPONENT_COLS,
                component_rows,
                replace=True,
                commit=commit)

            # Add all components to IssueSnapshot2Hotlist.
            # This is raw SQL to obviate passing FeaturesService down through
            #   the call stack wherever this function is called.
            # TODO(jrobbins): sort out dependencies between service classes.
            cnxn.Execute(
                '''
        INSERT INTO IssueSnapshot2Hotlist (issuesnapshot_id, hotlist_id)
        SELECT %s, hotlist_id FROM Hotlist2Issue WHERE issue_id = %s
      ''', [issuesnapshot_id, issue.issue_id])