def __init__(self, timestamp, days_only=False):
    values = []
    if timestamp:
      date_str = timestr.FormatRelativeDate(timestamp, days_only=days_only)
      if not date_str:
        date_str = timestr.FormatAbsoluteDate(timestamp)
      values = [date_str]

    TableCell.__init__(self, CELL_TYPE_UNFILTERABLE, values)
Exemple #2
0
  def _GetUserViewAndFormattedTime(self, mr, user_id, timestamp):
    formatted_time = (timestr.FormatAbsoluteDate(timestamp)
                      if timestamp else None)
    user = self.services.user.GetUser(mr.cnxn, user_id) if user_id else None
    user_view = None
    if user:
      user_view = framework_views.UserView(user)
      viewing_self = mr.auth.user_id == user_id
      # Do not obscure email if current user is a site admin. Do not obscure
      # email if current user is the same as the creator. For all other
      # cases do whatever obscure_email setting for the user is.
      email_obscured = (not(mr.auth.user_pb.is_site_admin or viewing_self)
                        and user_view.obscure_email)
      if not email_obscured:
        user_view.RevealEmail()

    return user_view, formatted_time
Exemple #3
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)
Exemple #4
0
    def __init__(self,
                 project_name,
                 comment_pb,
                 users_by_id,
                 autolink,
                 all_referenced_artifacts,
                 mr,
                 issue,
                 effective_ids=None):
        """Get IssueComment PB and make its fields available as attrs.

    Args:
      project_name: Name of the project this issue belongs to.
      comment_pb: Comment protocol buffer.
      users_by_id: dict mapping user_ids to UserViews, including
          the user that entered the comment, and any changed participants.
      autolink: utility object for automatically linking to other
        issues, git revisions, etc.
      all_referenced_artifacts: opaque object with details of referenced
        artifacts that is needed by autolink.
      mr: common information parsed from the HTTP request.
      issue: Issue PB for the issue that this comment is part of.
      effective_ids: optional set of int user IDs for the comment author.
    """
        super(IssueCommentView, self).__init__(comment_pb)

        self.id = comment_pb.id
        self.creator = users_by_id[comment_pb.user_id]

        # TODO(jrobbins): this should be based on the issue project, not the
        # request project for non-project views and cross-project.
        if mr.project:
            self.creator_role = framework_helpers.GetRoleName(
                effective_ids or {self.creator.user_id}, mr.project)
        else:
            self.creator_role = None

        time_tuple = time.localtime(comment_pb.timestamp)
        self.date_string = timestr.FormatAbsoluteDate(
            comment_pb.timestamp, old_format=timestr.MONTH_DAY_YEAR_FMT)
        self.date_relative = timestr.FormatRelativeDate(comment_pb.timestamp)
        self.date_tooltip = time.asctime(time_tuple)
        self.date_yyyymmdd = timestr.FormatAbsoluteDate(
            comment_pb.timestamp,
            recent_format=timestr.MONTH_DAY_YEAR_FMT,
            old_format=timestr.MONTH_DAY_YEAR_FMT)
        self.text_runs = _ParseTextRuns(comment_pb.content)
        if autolink and not comment_pb.deleted_by:
            self.text_runs = autolink.MarkupAutolinks(
                mr, self.text_runs, all_referenced_artifacts)

        self.attachments = [
            AttachmentView(attachment, project_name)
            for attachment in comment_pb.attachments
        ]
        self.amendments = sorted(
            [
                AmendmentView(amendment, users_by_id, mr.project_name)
                for amendment in comment_pb.amendments
            ],
            key=lambda amendment: amendment.field_name.lower())
        # Treat comments from banned users as being deleted.
        self.is_deleted = (comment_pb.deleted_by
                           or (self.creator and self.creator.banned))
        self.can_delete = False

        # TODO(jrobbins): pass through config to get granted permissions.
        perms = permissions.UpdateIssuePermissions(mr.perms, mr.project, issue,
                                                   mr.auth.effective_ids)
        if mr.auth.user_id and mr.project:
            self.can_delete = permissions.CanDeleteComment(
                comment_pb, self.creator, mr.auth.user_id, perms)

        self.visible = permissions.CanViewComment(comment_pb, self.creator,
                                                  mr.auth.user_id, perms)
Exemple #5
0
def GetSortedHotlistIssues(mr, hotlist_issues, issues_list, harmonized_config,
                           profiler, services):
    with profiler.Phase('Checking issue permissions and getting ranks'):

        allowed_issues = FilterIssues(mr, issues_list, services)
        allowed_iids = [issue.issue_id for issue in allowed_issues]
        # The values for issues in a hotlist are specific to the hotlist
        # (rank, adder, added) without invalidating the keys, an issue will retain
        # the rank value it has in one hotlist when navigating to another hotlist.
        sorting.InvalidateArtValuesKeys(
            mr.cnxn, [issue.issue_id for issue in allowed_issues])
        sorted_ranks = sorted([
            hotlist_issue.rank for hotlist_issue in hotlist_issues
            if hotlist_issue.issue_id in allowed_iids
        ])
        friendly_ranks = {
            rank: friendly
            for friendly, rank in enumerate(sorted_ranks, 1)
        }
        issue_adders = framework_views.MakeAllUserViews(
            mr.cnxn, services.user,
            [hotlist_issue.adder_id for hotlist_issue in hotlist_issues])
        hotlist_issues_context = {
            hotlist_issue.issue_id: {
                'issue_rank': friendly_ranks[hotlist_issue.rank],
                'adder_id': hotlist_issue.adder_id,
                'date_added':
                timestr.FormatAbsoluteDate(hotlist_issue.date_added),
                'note': hotlist_issue.note
            }
            for hotlist_issue in hotlist_issues
            if hotlist_issue.issue_id in allowed_iids
        }

    with profiler.Phase('Making user views'):
        issues_users_by_id = framework_views.MakeAllUserViews(
            mr.cnxn, services.user,
            tracker_bizobj.UsersInvolvedInIssues(allowed_issues or []))
        issues_users_by_id.update(issue_adders)

    with profiler.Phase('Sorting issues'):
        sortable_fields = tracker_helpers.SORTABLE_FIELDS.copy()
        sortable_fields.update({
            'rank':
            lambda issue: hotlist_issues_context[issue.issue_id]['issue_rank'],
            'adder':
            lambda issue: hotlist_issues_context[issue.issue_id]['adder_id'],
            'added':
            lambda issue: hotlist_issues_context[issue.issue_id]['date_added'],
            'note':
            lambda issue: hotlist_issues_context[issue.issue_id]['note']
        })
        sortable_postproc = tracker_helpers.SORTABLE_FIELDS_POSTPROCESSORS.copy(
        )
        sortable_postproc.update({
            'adder': lambda user_view: user_view.email,
        })
        if not mr.sort_spec:
            mr.sort_spec = 'rank'
        sorted_issues = sorting.SortArtifacts(mr,
                                              allowed_issues,
                                              harmonized_config,
                                              sortable_fields,
                                              sortable_postproc,
                                              users_by_id=issues_users_by_id,
                                              tie_breakers=['rank', 'id'])
        return sorted_issues, hotlist_issues_context, issues_users_by_id
Exemple #6
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)
Exemple #7
0
 def GetDate(*args):
     date = datetime.datetime(*args)
     return timestr.FormatAbsoluteDate(calendar.timegm(
         date.utctimetuple()),
                                       clock=lambda: now)