コード例 #1
0
ファイル: tracker_views.py プロジェクト: xinghun61/infra
def MakeBounceFieldValueViews(field_vals, phase_field_vals, config):
    """Return a list of field values to display on a validation bounce page."""
    field_value_views = []
    for fd in config.field_defs:
        if fd.field_id in field_vals:
            # TODO(jrobbins): also bounce derived values.
            val_items = [
                template_helpers.EZTItem(val=v, docstring='', idx=idx)
                for idx, v in enumerate(field_vals[fd.field_id])
            ]
            field_value_views.append(
                FieldValueView(fd,
                               config,
                               val_items, [],
                               None,
                               applicable=True))
        elif fd.field_id in phase_field_vals:
            vals_by_phase_name = phase_field_vals.get(fd.field_id)
            for phase_name, values in vals_by_phase_name.items():
                val_items = [
                    template_helpers.EZTItem(val=v, docstring='', idx=idx)
                    for idx, v in enumerate(values)
                ]
                field_value_views.append(
                    FieldValueView(fd,
                                   config,
                                   val_items, [],
                                   None,
                                   applicable=False,
                                   phase_name=phase_name))

    return field_value_views
コード例 #2
0
ファイル: issuelist.py プロジェクト: xinghun61/infra
  def GetTableViewData(
      self, mr, results, config, users_by_id, starred_iid_set, related_issues,
      viewable_iids_set):
    """EZT template values to render a Table View of issues.

    Args:
      mr: commonly used info parsed from the request.
      results: list of Issue PBs for the search results to be displayed.
      config: The ProjectIssueConfig PB for the current project.
      users_by_id: A dictionary {user_id: UserView} for all the users
      involved in results.
      starred_iid_set: Set of issues that the user has starred.
      related_issues: dict {issue_id: issue} of pre-fetched related issues.
      viewable_iids_set: set of issue ids that are viewable by the user.

    Returns:
      Dictionary of page data for rendering of the Table View.
    """
    # We need ordered_columns because EZT loops have no loop-counter available.
    # And, we use column number in the Javascript to hide/show columns.
    columns = mr.col_spec.split()
    ordered_columns = [template_helpers.EZTItem(col_index=i, name=col)
                       for i, col in enumerate(columns)]
    unshown_columns = table_view_helpers.ComputeUnshownColumns(
        results, columns, config, tracker_constants.OTHER_BUILT_IN_COLS)

    lower_columns = mr.col_spec.lower().split()
    lower_group_by = mr.group_by_spec.lower().split()
    table_data = _MakeTableData(
        results, starred_iid_set, lower_columns, lower_group_by,
        users_by_id, self.GetCellFactories(), related_issues,
        viewable_iids_set, config)

    # Used to offer easy filtering of each unique value in each column.
    column_values = table_view_helpers.ExtractUniqueValues(
        lower_columns, results, users_by_id, config, related_issues)

    table_view_data = {
        'table_data': table_data,
        'column_values': column_values,
        # Put ordered_columns inside a list of exactly 1 panel so that
        # it can work the same as the dashboard initial panel list headers.
        'panels': [template_helpers.EZTItem(ordered_columns=ordered_columns)],
        'unshown_columns': unshown_columns,
        'cursor': mr.cursor or mr.preview,
        'preview': mr.preview,
        'default_colspec': tracker_constants.DEFAULT_COL_SPEC,
        'default_results_per_page': tracker_constants.DEFAULT_RESULTS_PER_PAGE,
        'csv_link': framework_helpers.FormatURL(
            [(name, mr.GetParam(name)) for name in
             framework_helpers.RECOGNIZED_PARAMS],
            'csv', num=settings.max_artifact_search_results_per_page),
        'preview_on_hover': ezt.boolean(
            _ShouldPreviewOnHover(mr.auth.user_pb)),
        }
    return table_view_data
コード例 #3
0
    def GetTableViewData(self, mr):
        """EZT template values to render a Table View of issues.

    Args:
      mr: commonly used info parsed from the request.

    Returns:
      Dictionary of page data for rendering of the Table View.
    """
        table_data, table_related_dict = hotlist_helpers.CreateHotlistTableData(
            mr, mr.hotlist.items, self.services)
        columns = mr.col_spec.split()
        ordered_columns = [
            template_helpers.EZTItem(col_index=i, name=col)
            for i, col in enumerate(columns)
        ]
        table_view_data = {
            'table_data':
            table_data,
            'panels':
            [template_helpers.EZTItem(ordered_columns=ordered_columns)],
            'cursor':
            mr.cursor or mr.preview,
            'preview':
            mr.preview,
            'default_colspec':
            features_constants.DEFAULT_COL_SPEC,
            'default_results_per_page':
            10,
            'preview_on_hover': (settings.enable_quick_edit
                                 and mr.auth.user_pb.preview_on_hover),
            # token must be generated using url with userid to accommodate
            # multiple urls for one hotlist
            'edit_hotlist_token':
            xsrf.GenerateToken(
                mr.auth.user_id,
                hotlist_helpers.GetURLOfHotlist(mr.cnxn,
                                                mr.hotlist,
                                                self.services.user,
                                                url_for_token=True) + '.do'),
            'add_local_ids':
            '',
            'placeholder':
            _INITIAL_ADD_ISSUES_MESSAGE,
            'add_issues_selected':
            ezt.boolean(False),
            'col_spec':
            ''
        }
        table_view_data.update(table_related_dict)

        return table_view_data
コード例 #4
0
 def testSomeValues(self):
     """We can create a FieldValueView with some values."""
     values = [template_helpers.EZTItem(val=12, docstring=None, idx=0)]
     derived_values = [
         template_helpers.EZTItem(val=88, docstring=None, idx=0)
     ]
     estdays_fvv = tracker_views.FieldValueView(self.estdays_fd,
                                                self.config, values,
                                                derived_values, ['defect'])
     self.assertEqual(values, estdays_fvv.values)
     self.assertEqual(derived_values, estdays_fvv.derived_values)
     self.assertEqual('', estdays_fvv.phase_name)
     self.assertEqual(ezt.boolean(False),
                      estdays_fvv.field_def.is_phase_field)
コード例 #5
0
ファイル: servlet.py プロジェクト: xinghun61/infra
    def MakePagePerms(self, mr, art, *perm_list, **kwargs):
        """Make an EZTItem with a set of permissions needed in a given template.

    Args:
      mr: commonly used info parsed from the request.
      art: a project artifact, such as an issue.
      *perm_list: any number of permission names that are referenced
          in the EZT template.
      **kwargs: dictionary that may include 'granted_perms' list of permissions
          granted to the current user specifically on the current page.

    Returns:
      An EZTItem with one attribute for each permission and the value
      of each attribute being an ezt.boolean().  True if the user
      is permitted to do that action on the given artifact, or
      False if not.
    """
        granted_perms = kwargs.get('granted_perms')
        page_perms = template_helpers.EZTItem()
        for perm in perm_list:
            setattr(
                page_perms, perm,
                ezt.boolean(
                    self.CheckPerm(mr,
                                   perm,
                                   art=art,
                                   granted_perms=granted_perms)))

        return page_perms
コード例 #6
0
ファイル: table_view_helpers.py プロジェクト: xinghun61/infra
    def __init__(self,
                 cell_type,
                 explicit_values,
                 derived_values=None,
                 non_column_labels=None,
                 align='',
                 sort_values=True):
        """Store all the given data for later access by EZT."""
        self.type = cell_type
        self.align = align
        self.col_index = 0  # Is set afterward
        self.values = []
        if non_column_labels:
            self.non_column_labels = [
                template_helpers.EZTItem(value=v, is_derived=ezt.boolean(d))
                for v, d in non_column_labels
            ]
        else:
            self.non_column_labels = []

        for v in (sorted(explicit_values) if sort_values else explicit_values):
            self.values.append(CellItem(v))

        if derived_values:
            for v in (sorted(derived_values)
                      if sort_values else derived_values):
                self.values.append(CellItem(v, is_derived=True))
コード例 #7
0
def GetBannerTime(timestamp):
  """Converts a timestamp into EZT-ready data so it can appear in the banner.

  Args:
    timestamp: timestamp expressed in the following format:
         [year,month,day,hour,minute,second]
         e.g. [2009,3,20,21,45,50] represents March 20 2009 9:45:50 PM

  Returns:
    EZT-ready data used to display the time inside the banner message.
  """
  if timestamp is None:
    return None

  # Get the weekday and 'hour:min AM/PM' to display the timestamp
  # to users with javascript disabled
  ts = datetime.datetime(*[int(t) for t in timestamp])
  weekday = _WEEKDAY[ts.weekday()]
  hour_min = datetime.datetime.strftime(ts, '%I:%M%p')

  # Convert the timestamp to milliseconds since the epoch to display
  # the timestamp to users with javascript
  ts_ms = time.mktime(ts.timetuple()) * 1000

  return template_helpers.EZTItem(
      ts=ts_ms, year=ts.year, month=ts.month, day=ts.day, hour=ts.hour,
      minute=ts.minute, second=ts.second, weekday=weekday, hour_min=hour_min)
コード例 #8
0
 def IssueViewFactory(issue):
     return template_helpers.EZTItem(summary=issue.summary,
                                     local_id=issue.local_id,
                                     issue_id=issue.issue_id,
                                     status=issue.status
                                     or issue.derived_status,
                                     starred=None)
コード例 #9
0
def DecorateIssueClassifierQueue(
    cnxn, issue_service, spam_service, user_service, moderation_items):
  issue_ids = [item.issue_id for item in moderation_items]
  issues = issue_service.GetIssues(cnxn, issue_ids)
  issue_map = {}
  for issue in issues:
    issue_map[issue.issue_id] = issue

  flag_counts = spam_service.LookupIssueFlagCounts(cnxn, issue_ids)

  reporter_ids = [issue.reporter_id for issue in issues]
  reporters = user_service.GetUsersByIDs(cnxn, reporter_ids)
  comments = issue_service.GetCommentsForIssues(cnxn, issue_ids)

  items = []
  for item in moderation_items:
    issue=issue_map[item.issue_id]
    first_comment = comments.get(item.issue_id, ["[Empty]"])[0]

    items.append(template_helpers.EZTItem(
        issue=issue,
        summary=template_helpers.FitUnsafeText(issue.summary, 80),
        comment_text=template_helpers.FitUnsafeText(first_comment.content, 80),
        reporter=reporters[issue.reporter_id],
        flag_count=flag_counts.get(issue.issue_id, 0),
        is_spam=ezt.boolean(item.is_spam),
        verdict_time=item.verdict_time,
        classifier_confidence=item.classifier_confidence,
        reason=item.reason,
    ))

  return items
コード例 #10
0
  def GatherPageData(self, mr):
    """Build up a dictionary of data values to use when rendering the page.

    Args:
      mr: commonly usef info parsed from the request.

    Returns:
      Dict of values used by EZT for rendering the page.
    """
    with self.profiler.Phase('getting hotlist'):
      if mr.hotlist_id is None:
        self.abort(404, 'no hotlist specified')
    if mr.auth.user_id:
      self.services.user.AddVisitedHotlist(
          mr.cnxn, mr.auth.user_id, mr.hotlist_id)

    if mr.mode == 'grid':
      page_data = self.GetGridViewData(mr)
    else:
      page_data = self.GetTableViewData(mr)

    with self.profiler.Phase('making page perms'):
      owner_permissions = permissions.CanAdministerHotlist(
          mr.auth.effective_ids, mr.hotlist)
      editor_permissions = permissions.CanEditHotlist(
          mr.auth.effective_ids, mr.hotlist)
      # TODO(jojwang): each issue should have an individual
      # SetStar status based on its project to indicate whether or not
      # the star icon should be shown to the user.
      page_perms = template_helpers.EZTItem(
          EditIssue=None, SetStar=mr.auth.user_id)

    allow_rerank = (not mr.group_by_spec and mr.sort_spec.startswith(
        'rank') and (owner_permissions or editor_permissions))

    user_hotlists = self.services.features.GetHotlistsByUserID(
        mr.cnxn, mr.auth.user_id)
    try:
      user_hotlists.remove(self.services.features.GetHotlist(
          mr.cnxn, mr.hotlist_id))
    except ValueError:
      pass
    # Note: The HotlistView is created and returned in servlet.py
    page_data.update({'owner_permissions': ezt.boolean(owner_permissions),
                      'editor_permissions': ezt.boolean(editor_permissions),
                      'issue_tab_mode': 'issueList',
                      'grid_mode': ezt.boolean(mr.mode == 'grid'),
                      'set_star_token': '', # needed for shared ezt templates.
                      'page_perms': page_perms,
                      'colspec': mr.col_spec,
                      'allow_rerank': ezt.boolean(allow_rerank),
                      'csv_link': framework_helpers.FormatURL(
                          mr, '%d/csv' % mr.hotlist_id, num=100),
                      'is_hotlist': ezt.boolean(True),
                      'col_spec': mr.col_spec.lower(),
                      'user_hotlists': user_hotlists,
                      'viewing_user_page': ezt.boolean(True),
                      })
    return page_data
コード例 #11
0
ファイル: tracker_views.py プロジェクト: xinghun61/infra
def _MakeFieldValueItems(field_values, users_by_id):
    """Make appropriate int, string, or user values in the given fields."""
    result = []
    for fv in field_values:
        val = tracker_bizobj.GetFieldValue(fv, users_by_id)
        result.append(
            template_helpers.EZTItem(val=val, docstring=val, idx=len(result)))

    return result
コード例 #12
0
    def testDictionaryProxy(self):

        # basic in 'n out test
        item = template_helpers.EZTItem(label='foo', group_name='bar')

        self.assertEquals('foo', item.label)
        self.assertEquals('bar', item.group_name)

        # be sure the __str__ returns the fields
        self.assertEquals("EZTItem({'group_name': 'bar', 'label': 'foo'})",
                          str(item))
コード例 #13
0
def FindFieldValues(field_values, field_id, users_by_id):
  """Accumulate appropriate int, string, or user values in the given fields."""
  result = []
  for fv in field_values:
    if fv.field_id != field_id:
      continue

    val = tracker_bizobj.GetFieldValue(fv, users_by_id)
    result.append(template_helpers.EZTItem(
        val=val, docstring=val, idx=len(result)))

  return result
コード例 #14
0
ファイル: issuepeek.py プロジェクト: asdfghjjklllllaaa/infra
  def GetPreviousLocations(self, mr, issue):
    """Return a list of previous locations of the current issue."""
    previous_location_ids = self.services.issue.GetPreviousLocations(
        mr.cnxn, issue)
    previous_locations = []
    for old_pid, old_id in previous_location_ids:
      old_project = self.services.project.GetProject(mr.cnxn, old_pid)
      previous_locations.append(
          template_helpers.EZTItem(
              project_name=old_project.project_name, local_id=old_id))

    return previous_locations
コード例 #15
0
    def testMakeBounceFieldValueViews(self):
        config = tracker_pb2.ProjectIssueConfig()
        fd = tracker_pb2.FieldDef(field_id=3,
                                  field_type=tracker_pb2.FieldTypes.INT_TYPE,
                                  applicable_type='',
                                  field_name='EstDays')
        phase_fd = tracker_pb2.FieldDef(
            field_id=4,
            field_type=tracker_pb2.FieldTypes.INT_TYPE,
            applicable_type='',
            field_name='Gump')
        config.field_defs = [
            fd, phase_fd,
            tracker_pb2.FieldDef(field_id=5,
                                 field_type=tracker_pb2.FieldTypes.STR_TYPE)
        ]
        parsed_fvs = {3: [455]}
        parsed_phase_fvs = {
            4: {
                'stable': [73, 74],
                'beta': [8],
                'beta-exp': [75]
            },
        }
        fvs = tracker_views.MakeBounceFieldValueViews(parsed_fvs,
                                                      parsed_phase_fvs, config)

        self.assertEqual(len(fvs), 4)

        estdays_ezt_fv = template_helpers.EZTItem(val=455, docstring='', idx=0)
        expected = tracker_views.FieldValueView(fd, config, [estdays_ezt_fv],
                                                [], [])
        self.assertEqual(fvs[0].field_name, expected.field_name)
        self.assertEqual(fvs[0].values[0].val, expected.values[0].val)
        self.assertEqual(fvs[0].values[0].idx, expected.values[0].idx)
        self.assertTrue(fvs[0].applicable)

        self.assertEqual(fvs[1].field_name, phase_fd.field_name)
        self.assertEqual(fvs[2].field_name, phase_fd.field_name)
        self.assertEqual(fvs[3].field_name, phase_fd.field_name)

        fd.approval_id = 23
        config.field_defs = [
            fd,
            tracker_pb2.FieldDef(
                field_id=23,
                field_name='Legal',
                field_type=tracker_pb2.FieldTypes.APPROVAL_TYPE)
        ]
        fvs = tracker_views.MakeBounceFieldValueViews(parsed_fvs, {}, config)
        self.assertTrue(fvs[0].applicable)
コード例 #16
0
  def _BuildComponentQuota(self, used_bytes, quota_bytes, field_name):
    """Return an object to easily display quota info in EZT."""
    if quota_bytes:
      used_percent = 100 * used_bytes // quota_bytes
    else:
      used_percent = 0

    quota_mb = quota_bytes // 1024 // 1024

    return template_helpers.EZTItem(
        used=template_helpers.BytesKbOrMb(used_bytes),
        quota_mb=quota_mb,
        used_percent=used_percent,
        avail_percent=100 - used_percent,
        field_name=field_name)
コード例 #17
0
def _MakeExampleLabelGrid(label_list):
    """Return a list of EZTItems to make it easy to display example searches."""
    labels = label_list[:]  # Don't mess with the given labels.

    if len(labels) < 15:
        cols = 4
    elif len(labels) < 20:
        cols = 5
    else:
        cols = 6

    rows = []
    while labels:
        current_row = labels[:cols]
        labels = labels[cols:]
        rows.append(template_helpers.EZTItem(labels=current_row))

    return rows
コード例 #18
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)
コード例 #19
0
def _ConvertLabelsToFieldValues(label_values, field_name_lower, label_docs):
  """Iterate through the given labels and pull out values for the field.

  Args:
    label_values: a list of label strings for the given field.
    field_name_lower: lowercase string name of the custom field.
    label_docs: {lower_label: docstring} for well-known labels in the project.

  Returns:
    A list of EZT items with val and docstring fields.  One item is included
    for each label that matches the given field name.
  """
  values = []
  for idx, lab_val in enumerate(label_values):
    full_label_lower = '%s-%s' % (field_name_lower, lab_val.lower())
    values.append(template_helpers.EZTItem(
        val=lab_val, docstring=label_docs.get(full_label_lower, ''), idx=idx))

  return values
コード例 #20
0
def _LabelsMaskedOrNot(config, field_names, invert=False, trim_prefix=False):
    """Return EZTItems for labels that'd be masked. Or not, when invert=True."""
    field_names = [fn.lower() for fn in field_names]
    result = []
    for wkl in config.well_known_labels:
        masked_by = tracker_bizobj.LabelIsMaskedByField(wkl.label, field_names)
        if (masked_by and not invert) or (not masked_by and invert):
            display_name = wkl.label
            if trim_prefix:
                display_name = display_name[len(masked_by) + 1:]
            result.append(
                template_helpers.EZTItem(
                    name=display_name,
                    name_padded=display_name.ljust(20),
                    commented='#' if wkl.deprecated else '',
                    docstring=wkl.label_docstring,
                    docstring_short=template_helpers.FitUnsafeText(
                        wkl.label_docstring, 40),
                    idx=len(result)))

    return result
コード例 #21
0
    def GatherUnifiedSettingsPageData(cls, logged_in_user_id,
                                      settings_user_view, settings_user,
                                      settings_user_prefs):
        """Gather EZT variables needed for the unified user settings form.

    Args:
      logged_in_user_id: The user ID of the acting user.
      settings_user_view: The UserView of the target user.
      settings_user: The User PB of the target user.
      settings_user_prefs: UserPrefs object for the view user.

    Returns:
      A dictionary giving the names and values of all the variables to
      be exported to EZT to support the unified user settings form template.
    """

        settings_user_prefs_view = template_helpers.EZTItem(
            **{name: None
               for name in framework_bizobj.USER_PREF_DEFS})
        if settings_user_prefs:
            for upv in settings_user_prefs.prefs:
                if upv.value == 'true':
                    setattr(settings_user_prefs_view, upv.name, True)
                elif upv.value == 'false':
                    setattr(settings_user_prefs_view, upv.name, None)

        logging.info('settings_user_prefs_view is %r' %
                     settings_user_prefs_view)
        return {
            'settings_user': settings_user_view,
            'settings_user_pb': template_helpers.PBProxy(settings_user),
            'settings_user_is_banned': ezt.boolean(settings_user.banned),
            'self':
            ezt.boolean(logged_in_user_id == settings_user_view.user_id),
            'profile_url_fragment':
            (settings_user_view.profile_url[len('/u/'):]),
            'preview_on_hover': ezt.boolean(settings_user.preview_on_hover),
            'settings_user_prefs': settings_user_prefs_view,
        }
コード例 #22
0
def _ConvertLabelsToFieldValues(labels, field_name_lower, label_docs):
  """Iterate through the given labels and pull out values for the field.

  Args:
    labels: a list of label strings.
    field_name_lower: lowercase string name of the custom field.
    label_docs: {label: docstring} for well-known labels in the project.

  Returns:
    A list of EZT items with val and docstring fields.  One item is included
    for each label that matches the given field name.
  """
  values = []
  field_delim = field_name_lower + '-'
  for idx, lab in enumerate(labels):
    if lab.lower().startswith(field_delim):
      val = lab[len(field_delim):]
      # Use ellipsis in the display val if the val is too long.
      val_short = template_helpers.FitUnsafeText(str(val), 20)
      values.append(template_helpers.EZTItem(
          val=val, val_short=val_short, docstring=label_docs.get(lab, ''),
          idx=idx))

  return values
コード例 #23
0
    def GatherPageData(self, mr):
        """Build up a dictionary of data values to use when rendering the page.

    Args:
      mr: commonly used info parsed from the request.

    Returns:
      Dict of values used by EZT for rendering the page.
    """
        with mr.profiler.Phase('getting issues'):
            if not mr.local_id_list:
                raise exceptions.InputException()
            requested_issues = self.services.issue.GetIssuesByLocalIDs(
                mr.cnxn, mr.project_id, sorted(mr.local_id_list))

        with mr.profiler.Phase('filtering issues'):
            # TODO(jrobbins): filter out issues that the user cannot edit and
            # provide that as feedback rather than just siliently ignoring them.
            open_issues, closed_issues = (
                tracker_helpers.GetAllowedOpenedAndClosedIssues(
                    mr, [issue.issue_id for issue in requested_issues],
                    self.services))
            issues = open_issues + closed_issues

        if not issues:
            self.abort(404, 'no issues found')

        config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        type_label_set = {
            lab.lower()
            for lab in issues[0].labels if lab.lower().startswith('type-')
        }
        for issue in issues[1:]:
            new_type_set = {
                lab.lower()
                for lab in issue.labels if lab.lower().startswith('type-')
            }
            type_label_set &= new_type_set

        issue_phases = list(
            itertools.chain.from_iterable(issue.phases for issue in issues))

        field_views = tracker_views.MakeAllFieldValueViews(config,
                                                           type_label_set, [],
                                                           [], {},
                                                           phases=issue_phases)
        # Explicitly set all field views to not required. We do not want to force
        # users to have to set it for issues missing required fields.
        # See https://bugs.chromium.org/p/monorail/issues/detail?id=500 for more
        # details.
        for fv in field_views:
            fv.field_def.is_required_bool = None

        with mr.profiler.Phase('making issue proxies'):
            issue_views = [
                template_helpers.EZTItem(
                    local_id=issue.local_id,
                    summary=issue.summary,
                    closed=ezt.boolean(issue in closed_issues))
                for issue in issues
            ]

        num_seconds = (int(len(issue_views) * self._SECONDS_PER_UPDATE) +
                       self._SECONDS_OVERHEAD)

        page_perms = self.MakePagePerms(mr, None, permissions.CREATE_ISSUE,
                                        permissions.DELETE_ISSUE)

        return {
            'issue_tab_mode':
            'issueBulkEdit',
            'issues':
            issue_views,
            'local_ids_str':
            ','.join([str(issue.local_id) for issue in issues]),
            'num_issues':
            len(issue_views),
            'show_progress':
            ezt.boolean(num_seconds > self._SLOWNESS_THRESHOLD),
            'num_seconds':
            num_seconds,
            'initial_blocked_on':
            '',
            'initial_blocking':
            '',
            'initial_comment':
            '',
            'initial_status':
            '',
            'initial_owner':
            '',
            'initial_merge_into':
            '',
            'initial_cc':
            '',
            'initial_components':
            '',
            'labels': [],
            'fields':
            field_views,
            'restrict_to_known':
            ezt.boolean(config.restrict_to_known),
            'page_perms':
            page_perms,
            'statuses_offer_merge':
            config.statuses_offer_merge,
            'issue_phase_names':
            list({phase.name.lower()
                  for phase in issue_phases}),
        }
コード例 #24
0
ファイル: tracker_views.py プロジェクト: xinghun61/infra
    def __init__(self, mr, template, user_service, config):
        super(IssueTemplateView, self).__init__(template)

        self.ownername = ''
        try:
            self.owner_view = framework_views.MakeUserView(
                mr.cnxn, user_service, template.owner_id)
        except exceptions.NoSuchUserException:
            self.owner_view = None
        if self.owner_view:
            self.ownername = self.owner_view.email

        self.admin_views = list(
            framework_views.MakeAllUserViews(mr.cnxn, user_service,
                                             template.admin_ids).values())
        self.admin_names = ', '.join(
            sorted([admin_view.email for admin_view in self.admin_views]))

        self.summary_must_be_edited = ezt.boolean(
            template.summary_must_be_edited)
        self.members_only = ezt.boolean(template.members_only)
        self.owner_defaults_to_member = ezt.boolean(
            template.owner_defaults_to_member)
        self.component_required = ezt.boolean(template.component_required)

        component_paths = []
        for component_id in template.component_ids:
            component_paths.append(
                tracker_bizobj.FindComponentDefByID(component_id, config).path)
        self.components = ', '.join(component_paths)

        self.can_view = ezt.boolean(
            permissions.CanViewTemplate(mr.auth.effective_ids, mr.perms,
                                        mr.project, template))
        self.can_edit = ezt.boolean(
            permissions.CanEditTemplate(mr.auth.effective_ids, mr.perms,
                                        mr.project, template))

        field_name_set = {
            fd.field_name.lower()
            for fd in config.field_defs
            if fd.field_type is tracker_pb2.FieldTypes.ENUM_TYPE
            and not fd.is_deleted
        }  # TODO(jrobbins): restrictions
        non_masked_labels = [
            lab for lab in template.labels
            if not tracker_bizobj.LabelIsMaskedByField(lab, field_name_set)
        ]

        for i, label in enumerate(non_masked_labels):
            setattr(self, 'label%d' % i, label)
        for i in range(len(non_masked_labels), framework_constants.MAX_LABELS):
            setattr(self, 'label%d' % i, '')

        field_user_views = MakeFieldUserViews(mr.cnxn, template, user_service)

        self.field_values = []
        for fv in template.field_values:
            self.field_values.append(
                template_helpers.EZTItem(field_id=fv.field_id,
                                         val=tracker_bizobj.GetFieldValue(
                                             fv, field_user_views),
                                         idx=len(self.field_values)))

        self.complete_field_values = MakeAllFieldValueViews(
            config, template.labels, [], template.field_values,
            field_user_views)

        # Templates only display and edit the first value of multi-valued fields, so
        # expose a single value, if any.
        # TODO(jrobbins): Fully support multi-valued fields in templates.
        for idx, field_value_view in enumerate(self.complete_field_values):
            field_value_view.idx = idx
            if field_value_view.values:
                field_value_view.val = field_value_view.values[0].val
            else:
                field_value_view.val = None
コード例 #25
0
ファイル: table_view_helpers.py プロジェクト: xinghun61/infra
def ExtractUniqueValues(columns,
                        artifact_list,
                        users_by_id,
                        config,
                        related_issues,
                        hotlist_context_dict=None):
    """Build a nested list of unique values so the user can auto-filter.

  Args:
    columns: a list of lowercase column name strings, which may contain
        combined columns like "priority/pri".
    artifact_list: a list of artifacts in the complete set of search results.
    users_by_id: dict mapping user_ids to UserViews.
    config: ProjectIssueConfig PB for the current project.
    related_issues: dict {issue_id: issue} of pre-fetched related issues.
    hotlist_context_dict: dict for building a hotlist grid table

  Returns:
    [EZTItem(col1, colname1, [val11, val12,...]), ...]
    A list of EZTItems, each of which has a col_index, column_name,
    and a list of unique values that appear in that column.
  """
    column_values = {col_name: {} for col_name in columns}

    # For each combined column "a/b/c", add entries that point from "a" back
    # to "a/b/c", from "b" back to "a/b/c", and from "c" back to "a/b/c".
    combined_column_parts = collections.defaultdict(list)
    for col in columns:
        if '/' in col:
            for col_part in col.split('/'):
                combined_column_parts[col_part].append(col)

    unique_labels = set()
    for art in artifact_list:
        unique_labels.update(tracker_bizobj.GetLabels(art))

    for label in unique_labels:
        if '-' in label:
            col, val = label.split('-', 1)
            col = col.lower()
            if col in column_values:
                column_values[col][val.lower()] = val
            if col in combined_column_parts:
                for combined_column in combined_column_parts[col]:
                    column_values[combined_column][val.lower()] = val
        else:
            if 'summary' in column_values:
                column_values['summary'][label.lower()] = label

    # TODO(jrobbins): Consider refacting some of this to tracker_bizobj
    # or a new builtins.py to reduce duplication.
    if 'reporter' in column_values:
        for art in artifact_list:
            reporter_id = art.reporter_id
            if reporter_id and reporter_id in users_by_id:
                reporter_username = users_by_id[reporter_id].display_name
                column_values['reporter'][
                    reporter_username] = reporter_username

    if 'owner' in column_values:
        for art in artifact_list:
            owner_id = tracker_bizobj.GetOwnerId(art)
            if owner_id and owner_id in users_by_id:
                owner_username = users_by_id[owner_id].display_name
                column_values['owner'][owner_username] = owner_username

    if 'cc' in column_values:
        for art in artifact_list:
            cc_ids = tracker_bizobj.GetCcIds(art)
            for cc_id in cc_ids:
                if cc_id and cc_id in users_by_id:
                    cc_username = users_by_id[cc_id].display_name
                    column_values['cc'][cc_username] = cc_username

    if 'component' in column_values:
        for art in artifact_list:
            all_comp_ids = list(art.component_ids) + list(
                art.derived_component_ids)
            for component_id in all_comp_ids:
                cd = tracker_bizobj.FindComponentDefByID(component_id, config)
                if cd:
                    column_values['component'][cd.path] = cd.path

    if 'stars' in column_values:
        for art in artifact_list:
            star_count = art.star_count
            column_values['stars'][star_count] = star_count

    if 'status' in column_values:
        for art in artifact_list:
            status = tracker_bizobj.GetStatus(art)
            if status:
                column_values['status'][status.lower()] = status

    if 'project' in column_values:
        for art in artifact_list:
            project_name = art.project_name
            column_values['project'][project_name] = project_name

    if 'mergedinto' in column_values:
        for art in artifact_list:
            if art.merged_into and art.merged_into != 0:
                merged_issue = related_issues[art.merged_into]
                merged_issue_ref = tracker_bizobj.FormatIssueRef(
                    (merged_issue.project_name, merged_issue.local_id))
                column_values['mergedinto'][
                    merged_issue_ref] = merged_issue_ref

    if 'blocked' in column_values:
        for art in artifact_list:
            if art.blocked_on_iids:
                column_values['blocked']['is_blocked'] = 'Yes'
            else:
                column_values['blocked']['is_not_blocked'] = 'No'

    if 'blockedon' in column_values:
        for art in artifact_list:
            if art.blocked_on_iids:
                for blocked_on_iid in art.blocked_on_iids:
                    blocked_on_issue = related_issues[blocked_on_iid]
                    blocked_on_ref = tracker_bizobj.FormatIssueRef(
                        (blocked_on_issue.project_name,
                         blocked_on_issue.local_id))
                    column_values['blockedon'][blocked_on_ref] = blocked_on_ref

    if 'blocking' in column_values:
        for art in artifact_list:
            if art.blocking_iids:
                for blocking_iid in art.blocking_iids:
                    blocking_issue = related_issues[blocking_iid]
                    blocking_ref = tracker_bizobj.FormatIssueRef(
                        (blocking_issue.project_name, blocking_issue.local_id))
                    column_values['blocking'][blocking_ref] = blocking_ref

    if 'added' in column_values:
        for art in artifact_list:
            if hotlist_context_dict and hotlist_context_dict[art.issue_id]:
                issue_dict = hotlist_context_dict[art.issue_id]
                date_added = issue_dict['date_added']
                column_values['added'][date_added] = date_added

    if 'adder' in column_values:
        for art in artifact_list:
            if hotlist_context_dict and hotlist_context_dict[art.issue_id]:
                issue_dict = hotlist_context_dict[art.issue_id]
                adder_id = issue_dict['adder_id']
                adder = users_by_id[adder_id].display_name
                column_values['adder'][adder] = adder

    if 'note' in column_values:
        for art in artifact_list:
            if hotlist_context_dict and hotlist_context_dict[art.issue_id]:
                issue_dict = hotlist_context_dict[art.issue_id]
                note = issue_dict['note']
                if issue_dict['note']:
                    column_values['note'][note] = note

    if 'attachments' in column_values:
        for art in artifact_list:
            attachment_count = art.attachment_count
            column_values['attachments'][attachment_count] = attachment_count

    # Add all custom field values if the custom field name is a shown column.
    field_id_to_col = {}
    for art in artifact_list:
        for fv in art.field_values:
            field_col, field_type = field_id_to_col.get(
                fv.field_id, (None, None))
            if field_col == 'NOT_SHOWN':
                continue
            if field_col is None:
                fd = tracker_bizobj.FindFieldDefByID(fv.field_id, config)
                if not fd:
                    field_id_to_col[fv.field_id] = 'NOT_SHOWN', None
                    continue
                field_col = fd.field_name.lower()
                field_type = fd.field_type
                if field_col not in column_values:
                    field_id_to_col[fv.field_id] = 'NOT_SHOWN', None
                    continue
                field_id_to_col[fv.field_id] = field_col, field_type

            if field_type == tracker_pb2.FieldTypes.ENUM_TYPE:
                continue  # Already handled by label parsing
            elif field_type == tracker_pb2.FieldTypes.INT_TYPE:
                val = fv.int_value
            elif field_type == tracker_pb2.FieldTypes.STR_TYPE:
                val = fv.str_value
            elif field_type == tracker_pb2.FieldTypes.USER_TYPE:
                user = users_by_id.get(fv.user_id)
                val = user.email if user else framework_constants.NO_USER_NAME
            elif field_type == tracker_pb2.FieldTypes.DATE_TYPE:
                val = fv.int_value  # TODO(jrobbins): convert to date
            elif field_type == tracker_pb2.FieldTypes.BOOL_TYPE:
                val = 'Yes' if fv.int_value else 'No'

            column_values[field_col][val] = val

    # TODO(jrobbins): make the capitalization of well-known unique label and
    # status values match the way it is written in the issue config.

    # Return EZTItems for each column in left-to-right display order.
    result = []
    for i, col_name in enumerate(columns):
        # TODO(jrobbins): sort each set of column values top-to-bottom, by the
        # order specified in the project artifact config. For now, just sort
        # lexicographically to make expected output defined.
        sorted_col_values = sorted(column_values[col_name].values())
        result.append(
            template_helpers.EZTItem(col_index=i,
                                     column_name=col_name,
                                     filter_values=sorted_col_values))

    return result
コード例 #26
0
def MakeGridData(artifacts,
                 x_attr,
                 x_headings,
                 y_attr,
                 y_headings,
                 users_by_id,
                 artifact_view_factory,
                 all_label_values,
                 config,
                 related_issues,
                 hotlist_context_dict=None):
    """Return a list of grid row items for display by EZT.

  Args:
    artifacts: a list of issues to consider showing.
    x_attr: lowercase name of the attribute that defines the x-axis.
    x_headings: list of values for column headings.
    y_attr: lowercase name of the attribute that defines the y-axis.
    y_headings: list of values for row headings.
    users_by_id: dict {user_id: user_view, ...} for referenced users.
    artifact_view_factory: constructor for grid tiles.
    all_label_values: pre-parsed dictionary of values from the key-value
        labels on each issue: {issue_id: {key: [val,...], ...}, ...}
    config: ProjectIssueConfig PB for the current project.
    related_issues: dict {issue_id: issue} of pre-fetched related issues.
    hotlist_context_dict: dict{issue_id: {hotlist_item_field: field_value, ..}}

  Returns:
    A list of EZTItems, each representing one grid row, and each having
    a nested list of grid cells.

  Each grid row has a row name, and a list of cells.  Each cell has a
  list of tiles.  Each tile represents one artifact.  Artifacts are
  represented once in each cell that they match, so one artifact that
  has multiple values for a certain attribute can occur in multiple cells.
  """
    x_attr = x_attr.lower()
    y_attr = y_attr.lower()

    # A flat dictionary {(x, y): [cell, ...], ...] for the whole grid.
    x_y_data = collections.defaultdict(list)

    # Put each issue into the grid cell(s) where it belongs.
    for art in artifacts:
        if hotlist_context_dict:
            hotlist_issues_context = hotlist_context_dict[art.issue_id]
        else:
            hotlist_issues_context = None
        label_value_dict = all_label_values[art.local_id]
        x_vals = GetArtifactAttr(art,
                                 x_attr,
                                 users_by_id,
                                 label_value_dict,
                                 config,
                                 related_issues,
                                 hotlist_issue_context=hotlist_issues_context)
        y_vals = GetArtifactAttr(art,
                                 y_attr,
                                 users_by_id,
                                 label_value_dict,
                                 config,
                                 related_issues,
                                 hotlist_issue_context=hotlist_issues_context)
        tile = artifact_view_factory(art)

        # Put the current issue into each cell where it belongs, which will usually
        # be exactly 1 cell, but it could be a few.
        if x_attr != '--' and y_attr != '--':  # User specified both axes.
            for x in x_vals:
                for y in y_vals:
                    x_y_data[x, y].append(tile)
        elif y_attr != '--':  # User only specified Y axis.
            for y in y_vals:
                x_y_data['All', y].append(tile)
        elif x_attr != '--':  # User only specified X axis.
            for x in x_vals:
                x_y_data[x, 'All'].append(tile)
        else:  # User specified neither axis.
            x_y_data['All', 'All'].append(tile)

    # Convert the dictionary to a list-of-lists so that EZT can iterate over it.
    grid_data = []
    for y in y_headings:
        cells_in_row = []
        for x in x_headings:
            tiles = x_y_data[x, y]

            drill_down = ''
            if x_attr != '--':
                drill_down = MakeDrillDownSearch(x_attr, x)
            if y_attr != '--':
                drill_down += MakeDrillDownSearch(y_attr, y)

            cells_in_row.append(
                template_helpers.EZTItem(tiles=tiles,
                                         count=len(tiles),
                                         drill_down=drill_down))
        grid_data.append(
            template_helpers.EZTItem(grid_y_heading=y,
                                     cells_in_row=cells_in_row))

    return grid_data
コード例 #27
0
ファイル: tracker_views.py プロジェクト: xinghun61/infra
    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)
コード例 #28
0
def GetGridViewData(mr,
                    results,
                    config,
                    users_by_id,
                    starred_iid_set,
                    grid_limited,
                    related_issues,
                    hotlist_context_dict=None):
    """EZT template values to render a Grid View of issues.
  Args:
    mr: commonly used info parsed from the request.
    results: The Issue PBs that are the search results to be displayed.
    config: The ProjectConfig PB for the project this view is in.
    users_by_id: A dictionary {user_id: user_view,...} for all the users
        involved in results.
    starred_iid_set: Set of issues that the user has starred.
    grid_limited: True if the results were limited to fit within the grid.
    related_issues: dict {issue_id: issue} of pre-fetched related issues.
    hotlist_context_dict: dict for building a hotlist grid table

  Returns:
    Dictionary for EZT template rendering of the Grid View.
  """
    # We need ordered_columns because EZT loops have no loop-counter available.
    # And, we use column number in the Javascript to hide/show columns.
    columns = mr.col_spec.split()
    ordered_columns = [
        template_helpers.EZTItem(col_index=i, name=col)
        for i, col in enumerate(columns)
    ]
    other_built_in_cols = (features_constants.OTHER_BUILT_IN_COLS
                           if hotlist_context_dict else
                           tracker_constants.OTHER_BUILT_IN_COLS)
    unshown_columns = table_view_helpers.ComputeUnshownColumns(
        results, columns, config, other_built_in_cols)

    grid_x_attr = (mr.x or config.default_x_attr or '--').lower()
    grid_y_attr = (mr.y or config.default_y_attr or '--').lower()
    all_label_values = {}
    for art in results:
        all_label_values[art.local_id] = (MakeLabelValuesDict(art))

    if grid_x_attr == '--':
        grid_x_headings = ['All']
    else:
        grid_x_items = table_view_helpers.ExtractUniqueValues(
            [grid_x_attr],
            results,
            users_by_id,
            config,
            related_issues,
            hotlist_context_dict=hotlist_context_dict)
        grid_x_headings = grid_x_items[0].filter_values
        if AnyArtifactHasNoAttr(results,
                                grid_x_attr,
                                users_by_id,
                                all_label_values,
                                config,
                                related_issues,
                                hotlist_context_dict=hotlist_context_dict):
            grid_x_headings.append(framework_constants.NO_VALUES)
        grid_x_headings = SortGridHeadings(grid_x_attr, grid_x_headings,
                                           users_by_id, config,
                                           tracker_helpers.SORTABLE_FIELDS)

    if grid_y_attr == '--':
        grid_y_headings = ['All']
    else:
        grid_y_items = table_view_helpers.ExtractUniqueValues(
            [grid_y_attr],
            results,
            users_by_id,
            config,
            related_issues,
            hotlist_context_dict=hotlist_context_dict)
        grid_y_headings = grid_y_items[0].filter_values
        if AnyArtifactHasNoAttr(results,
                                grid_y_attr,
                                users_by_id,
                                all_label_values,
                                config,
                                related_issues,
                                hotlist_context_dict=hotlist_context_dict):
            grid_y_headings.append(framework_constants.NO_VALUES)
        grid_y_headings = SortGridHeadings(grid_y_attr, grid_y_headings,
                                           users_by_id, config,
                                           tracker_helpers.SORTABLE_FIELDS)

    logging.info('grid_x_headings = %s', grid_x_headings)
    logging.info('grid_y_headings = %s', grid_y_headings)
    grid_data = PrepareForMakeGridData(
        results,
        starred_iid_set,
        grid_x_attr,
        grid_x_headings,
        grid_y_attr,
        grid_y_headings,
        users_by_id,
        all_label_values,
        config,
        related_issues,
        hotlist_context_dict=hotlist_context_dict)

    grid_axis_choice_dict = {}
    for oc in ordered_columns:
        grid_axis_choice_dict[oc.name] = True
    for uc in unshown_columns:
        grid_axis_choice_dict[uc] = True
    for bad_axis in tracker_constants.NOT_USED_IN_GRID_AXES:
        if bad_axis in grid_axis_choice_dict:
            del grid_axis_choice_dict[bad_axis]
    grid_axis_choices = grid_axis_choice_dict.keys()
    grid_axis_choices.sort()

    grid_cell_mode = mr.cells
    if len(results) > settings.max_tiles_in_grid and mr.cells == 'tiles':
        grid_cell_mode = 'ids'

    grid_view_data = {
        'grid_limited': ezt.boolean(grid_limited),
        'grid_shown': len(results),
        'grid_x_headings': grid_x_headings,
        'grid_y_headings': grid_y_headings,
        'grid_data': grid_data,
        'grid_axis_choices': grid_axis_choices,
        'grid_cell_mode': grid_cell_mode,
        'results': results,  # Really only useful in if-any.
    }
    return grid_view_data
コード例 #29
0
def GatherUpdatesData(services,
                      mr,
                      project_ids=None,
                      user_ids=None,
                      ending=None,
                      updates_page_url=None,
                      autolink=None,
                      highlight=None):
    """Gathers and returns updates data.

  Args:
    services: Connections to backend services.
    mr: HTTP request info, used by the artifact autolink.
    project_ids: List of project IDs we want updates for.
    user_ids: List of user IDs we want updates for.
    ending: Ending type for activity titles, 'in_project' or 'by_user'.
    updates_page_url: The URL that will be used to create pagination links from.
    autolink: Autolink instance.
    highlight: What to highlight in the middle column on user updates pages
        i.e. 'project', 'user', or None.
  """
    # num should be non-negative number
    num = mr.GetPositiveIntParam('num', UPDATES_PER_PAGE)
    num = min(num, MAX_UPDATES_PER_PAGE)

    updates_data = {
        'no_stars': None,
        'no_activities': None,
        'pagination': None,
        'updates_data': None,
        'ending_type': ending,
    }

    if not user_ids and not project_ids:
        updates_data['no_stars'] = ezt.boolean(True)
        return updates_data

    ascending = bool(mr.after)
    with mr.profiler.Phase('get activities'):
        comments = services.issue.GetIssueActivity(mr.cnxn,
                                                   num=num,
                                                   before=mr.before,
                                                   after=mr.after,
                                                   project_ids=project_ids,
                                                   user_ids=user_ids,
                                                   ascending=ascending)
        # Filter the comments based on permission to view the issue.
        # TODO(jrobbins): push permission checking in the query so that
        # pagination pages never become underfilled, or use backends to shard.
        # TODO(jrobbins): come back to this when I implement private comments.
        # TODO(jrobbins): it would be better if we could just get the dict directly.
        prefetched_issues_list = services.issue.GetIssues(
            mr.cnxn, {c.issue_id
                      for c in comments})
        prefetched_issues = {
            issue.issue_id: issue
            for issue in prefetched_issues_list
        }
        needed_project_ids = {
            issue.project_id
            for issue in prefetched_issues_list
        }
        prefetched_projects = services.project.GetProjects(
            mr.cnxn, needed_project_ids)
        prefetched_configs = services.config.GetProjectConfigs(
            mr.cnxn, needed_project_ids)
        viewable_issues_list = tracker_helpers.FilterOutNonViewableIssues(
            mr.auth.effective_ids, mr.auth.user_pb, prefetched_projects,
            prefetched_configs, prefetched_issues_list)
        viewable_iids = {issue.issue_id for issue in viewable_issues_list}
        comments = [c for c in comments if c.issue_id in viewable_iids]
        if ascending:
            comments.reverse()

    amendment_user_ids = []
    for comment in comments:
        for amendment in comment.amendments:
            amendment_user_ids.extend(amendment.added_user_ids)
            amendment_user_ids.extend(amendment.removed_user_ids)

    users_by_id = framework_views.MakeAllUserViews(
        mr.cnxn, services.user, [c.user_id for c in comments],
        amendment_user_ids)
    framework_views.RevealAllEmailsToMembers(mr.auth, mr.project, users_by_id)

    num_results_returned = len(comments)
    displayed_activities = comments[:UPDATES_PER_PAGE]

    if not num_results_returned:
        updates_data['no_activities'] = ezt.boolean(True)
        return updates_data

    # Get all referenced artifacts first
    all_ref_artifacts = None
    if autolink is not None:
        content_list = []
        for activity in comments:
            content_list.append(activity.content)

        all_ref_artifacts = autolink.GetAllReferencedArtifacts(
            mr, content_list)

    # Now process content and gather activities
    today = []
    yesterday = []
    pastweek = []
    pastmonth = []
    thisyear = []
    older = []

    with mr.profiler.Phase('rendering activities'):
        for activity in displayed_activities:
            entry = ActivityView(activity,
                                 mr,
                                 prefetched_issues,
                                 users_by_id,
                                 prefetched_projects,
                                 prefetched_configs,
                                 autolink=autolink,
                                 all_ref_artifacts=all_ref_artifacts,
                                 ending=ending,
                                 highlight=highlight)

            if entry.date_bucket == 'Today':
                today.append(entry)
            elif entry.date_bucket == 'Yesterday':
                yesterday.append(entry)
            elif entry.date_bucket == 'Last 7 days':
                pastweek.append(entry)
            elif entry.date_bucket == 'Last 30 days':
                pastmonth.append(entry)
            elif entry.date_bucket == 'Earlier this year':
                thisyear.append(entry)
            elif entry.date_bucket == 'Before this year':
                older.append(entry)

    new_after = None
    new_before = None
    if displayed_activities:
        new_after = displayed_activities[0].timestamp
        new_before = displayed_activities[-1].timestamp

    prev_url = None
    next_url = None
    if updates_page_url:
        list_servlet_rel_url = updates_page_url.split('/')[-1]
        recognized_params = [(name, mr.GetParam(name))
                             for name in framework_helpers.RECOGNIZED_PARAMS]
        if displayed_activities and (mr.before or mr.after):
            prev_url = framework_helpers.FormatURL(recognized_params,
                                                   list_servlet_rel_url,
                                                   after=new_after)
        if mr.after or len(comments) > UPDATES_PER_PAGE:
            next_url = framework_helpers.FormatURL(recognized_params,
                                                   list_servlet_rel_url,
                                                   before=new_before)

    if prev_url or next_url:
        pagination = template_helpers.EZTItem(start=None,
                                              last=None,
                                              prev_url=prev_url,
                                              next_url=next_url,
                                              reload_url=None,
                                              visible=ezt.boolean(True),
                                              total_count=None)
    else:
        pagination = None

    updates_data.update({
        'no_activities':
        ezt.boolean(False),
        'pagination':
        pagination,
        'updates_data':
        template_helpers.EZTItem(today=today,
                                 yesterday=yesterday,
                                 pastweek=pastweek,
                                 pastmonth=pastmonth,
                                 thisyear=thisyear,
                                 older=older),
    })

    return updates_data
コード例 #30
0
ファイル: issuepeek.py プロジェクト: asdfghjjklllllaaa/infra
  def GatherPageData(self, mr):
    """Build up a dictionary of data values to use when rendering the page.

    Args:
      mr: commonly used info parsed from the request.

    Returns:
      Dict of values used by EZT for rendering the page.
    """
    if mr.local_id is None:
      self.abort(404, 'no issue specified')
    with work_env.WorkEnv(mr, self.services) as we:
      # Signed in users could edit the issue, so it must be fresh.
      use_cache = not mr.auth.user_id
      issue = we.GetIssueByLocalID(
          mr.project_id, mr.local_id, use_cache=use_cache)

      # We give no explanation of missing issues on the peek page.
      if issue.deleted:
        self.abort(404, 'issue not found')

      star_cnxn = sql.MonorailConnection()
      star_promise = framework_helpers.Promise(
          we.IsIssueStarred, issue, cnxn=star_cnxn)

      config = we.GetProjectConfig(mr.project_id)
      comments = we.ListIssueComments(issue)

    descriptions, visible_comments, cmnt_pagination = PaginateComments(
        mr, issue, comments, config, self.services)

    with mr.profiler.Phase('making user proxies'):
      involved_user_ids = tracker_bizobj.UsersInvolvedInIssues([issue])
      group_ids = self.services.usergroup.DetermineWhichUserIDsAreGroups(
          mr.cnxn, involved_user_ids)
      comment_user_ids = tracker_bizobj.UsersInvolvedInCommentList(
          descriptions + visible_comments)
      users_by_id = framework_views.MakeAllUserViews(
          mr.cnxn, self.services.user, involved_user_ids,
          comment_user_ids, group_ids=group_ids)
      framework_views.RevealAllEmailsToMembers(mr.auth, mr.project, users_by_id)

    (issue_view, description_views,
     comment_views) = self._MakeIssueAndCommentViews(
         mr, issue, users_by_id, descriptions, visible_comments, config,
         issue_reporters=[], comment_reporters=[])

    with mr.profiler.Phase('getting starring info'):
      starred = star_promise.WaitAndGetValue()
      star_cnxn.Close()
      permit_edit = permissions.CanEditIssue(
          mr.auth.effective_ids, mr.perms, mr.project, issue)

    mr.ComputeColSpec(config)
    restrict_to_known = config.restrict_to_known

    page_perms = self.MakePagePerms(
        mr, issue,
        permissions.CREATE_ISSUE,
        permissions.SET_STAR,
        permissions.EDIT_ISSUE,
        permissions.EDIT_ISSUE_SUMMARY,
        permissions.EDIT_ISSUE_STATUS,
        permissions.EDIT_ISSUE_OWNER,
        permissions.EDIT_ISSUE_CC,
        permissions.DELETE_ISSUE,
        permissions.ADD_ISSUE_COMMENT,
        permissions.DELETE_OWN,
        permissions.DELETE_ANY,
        permissions.VIEW_INBOUND_MESSAGES)
    page_perms.EditIssue = ezt.boolean(permit_edit)

    prevent_restriction_removal = (
        mr.project.only_owners_remove_restrictions and
        not framework_bizobj.UserOwnsProject(
            mr.project, mr.auth.effective_ids))

    cmd_slots, default_slot_num = self.services.features.GetRecentCommands(
        mr.cnxn, mr.auth.user_id, mr.project_id)
    cmd_slot_views = [
        template_helpers.EZTItem(
            slot_num=slot_num, command=command, comment=comment)
        for slot_num, command, comment in cmd_slots]

    previous_locations = self.GetPreviousLocations(mr, issue)

    return {
        'issue_tab_mode': 'issueDetail',
        'issue': issue_view,
        'description': description_views,
        'comments': comment_views,
        'labels': issue.labels,
        'num_detail_rows': len(comment_views) + 4,
        'noisy': ezt.boolean(tracker_helpers.IsNoisy(
            len(comment_views), issue.star_count)),

        'cmnt_pagination': cmnt_pagination,
        'colspec': mr.col_spec,
        'searchtip': 'You can jump to any issue by number',
        'starred': ezt.boolean(starred),

        'pagegen': str(int(time.time() * 1000000)),

        'restrict_to_known': ezt.boolean(restrict_to_known),
        'prevent_restriction_removal': ezt.boolean(
            prevent_restriction_removal),

        'statuses_offer_merge': config.statuses_offer_merge,
        'page_perms': page_perms,
        'cmd_slots': cmd_slot_views,
        'default_slot_num': default_slot_num,
        'quick_edit_submit_url': tracker_helpers.FormatRelativeIssueURL(
            issue.project_name, urls.ISSUE_PEEK + '.do', id=issue.local_id),
        'previous_locations': previous_locations,
        # for template issue-meta-part shared by issuedetail servlet
        'user_remaining_hotlists': [],
        'user_issue_hotlists': [],
        'involved_users_issue_hotlists': [],
        'remaining_issue_hotlists': [],
        }