Esempio n. 1
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
Esempio n. 2
0
    def __init__(self, cnxn, services, component_def, users_by_id):
        super(ComponentDefView, self).__init__(component_def)

        c_path = component_def.path
        if '>' in c_path:
            self.parent_path = c_path[:c_path.rindex('>')]
            self.leaf_name = c_path[c_path.rindex('>') + 1:]
        else:
            self.parent_path = ''
            self.leaf_name = c_path

        self.docstring_short = template_helpers.FitUnsafeText(
            component_def.docstring, 200)

        self.admins = [
            users_by_id.get(admin_id) for admin_id in component_def.admin_ids
        ]
        self.cc = [users_by_id.get(cc_id) for cc_id in component_def.cc_ids]
        self.labels = [
            services.config.LookupLabel(cnxn, component_def.project_id,
                                        label_id)
            for label_id in component_def.label_ids
        ]
        self.classes = 'all '
        if self.parent_path == '':
            self.classes += 'toplevel '
        self.classes += 'deprecated ' if component_def.deprecated else 'active '
Esempio n. 3
0
  def __init__(self, user, is_group=False):
    self.user = user
    self.is_group = is_group
    email = user.email or ''
    self.user_id = user.user_id
    self.email = email
    if user.obscure_email:
      self.profile_url = '/u/%s/' % user.user_id
    else:
      self.profile_url = '/u/%s/' % email
    self.obscure_email = user.obscure_email
    self.banned = ''

    (self.username, self.domain,
     self.obscured_username) = ParseAndObscureAddress(email)
    # No need to obfuscate or reveal client email.
    # Instead display a human-readable username.
    if self.user_id == framework_constants.DELETED_USER_ID:
      self.display_name = framework_constants.DELETED_USER_NAME
      self.obscure_email = ''
      self.profile_url = ''
    elif self.email in client_config_svc.GetServiceAccountMap():
      self.display_name = client_config_svc.GetServiceAccountMap()[self.email]
    elif not self.obscure_email:
      self.display_name = email
    else:
      self.display_name = '%s...@%s' % (self.obscured_username, self.domain)

    self.avail_message, self.avail_state = (
        framework_helpers.GetUserAvailability(user, is_group))
    self.avail_message_short = template_helpers.FitUnsafeText(
        self.avail_message, 35)
Esempio n. 4
0
    def __init__(self,
                 fd,
                 config,
                 values,
                 derived_values,
                 issue_types,
                 applicable=None,
                 phase_name=None):
        """Make several values related to this field available as attrs.

    Args:
      fd: field definition to be displayed (or not, if no value).
      config: ProjectIssueConfig PB for the issue's project.
      values: list of explicit field values.
      derived_values: list of derived field values.
      issue_types: set of lowered string values from issues' "Type-*" labels.
      applicable: optional boolean that overrides the rule that determines
          when a field is applicable.
      phase_name: name of the phase this field value belongs to.
    """
        self.field_def = FieldDefView(fd, config)
        self.field_id = fd.field_id
        self.field_name = fd.field_name
        self.field_docstring = fd.docstring
        self.field_docstring_short = template_helpers.FitUnsafeText(
            fd.docstring, 60)
        self.phase_name = phase_name or ""

        self.values = values
        self.derived_values = derived_values

        self.applicable_type = fd.applicable_type
        if applicable is not None:
            self.applicable = ezt.boolean(applicable)
        else:
            # Note: We don't show approval types, approval sub fields, or
            # phase fields in ezt issue pages.
            if (fd.field_type == tracker_pb2.FieldTypes.APPROVAL_TYPE
                    or fd.approval_id or fd.is_phase_field):
                self.applicable = ezt.boolean(False)
            else:
                # A field is applicable to a given issue if it (a) applies to all,
                # issues or (b) already has a value on this issue, or (c) says that
                # it applies to issues with this type (or a prefix of it).
                applicable_type_lower = self.applicable_type.lower()
                self.applicable = ezt.boolean(
                    not self.applicable_type or values or any(
                        type_label.startswith(applicable_type_lower)
                        for type_label in issue_types))
            # TODO(jrobbins): also evaluate applicable_predicate

        self.display = ezt.boolean(  # or fd.show_empty
            self.values or self.derived_values
            or (self.applicable and not fd.is_niche))
Esempio n. 5
0
  def __init__(self, field_def, config, user_views=None):
    super(FieldDefView, self).__init__(field_def)

    self.type_name = str(field_def.field_type)

    self.choices = []
    if field_def.field_type == tracker_pb2.FieldTypes.ENUM_TYPE:
      self.choices = tracker_helpers.LabelsMaskedByFields(
          config, [field_def.field_name], trim_prefix=True)

    self.docstring_short = template_helpers.FitUnsafeText(
        field_def.docstring, 200)
    self.validate_help = None

    if field_def.is_required:
      self.importance = 'required'
    elif field_def.is_niche:
      self.importance = 'niche'
    else:
      self.importance = 'normal'

    if field_def.min_value is not None:
      self.min_value = field_def.min_value
      self.validate_help = 'Value must be >= %d' % field_def.min_value
    else:
      self.min_value = None  # Otherwise it would default to 0

    if field_def.max_value is not None:
      self.max_value = field_def.max_value
      self.validate_help = 'Value must be <= %d' % field_def.max_value
    else:
      self.max_value = None  # Otherwise it would default to 0

    if field_def.min_value is not None and field_def.max_value is not None:
      self.validate_help = 'Value must be between %d and %d' % (
          field_def.min_value, field_def.max_value)

    if field_def.regex:
      self.validate_help = 'Value must match regex: %s' % field_def.regex

    if field_def.needs_member:
      self.validate_help = 'Value must be a project member'

    if field_def.needs_perm:
      self.validate_help = (
          'Value must be a project member with permission %s' %
          field_def.needs_perm)

    self.date_action_str = str(field_def.date_action or 'no_action').lower()

    self.admins = []
    if user_views:
      self.admins = [user_views.get(admin_id)
                     for admin_id in field_def.admin_ids]
Esempio n. 6
0
    def __init__(self, component_id, config, derived):
        """Make the component name and docstring available as attrs.

    Args:
      component_id: int component_id to look up in the config
      config: ProjectIssueConfig PB for the issue's project.
      derived: True if this component was derived.
    """
        cd = tracker_bizobj.FindComponentDefByID(component_id, config)
        self.path = cd.path
        self.docstring = cd.docstring
        self.docstring_short = template_helpers.FitUnsafeText(cd.docstring, 60)
        self.derived = ezt.boolean(derived)
Esempio n. 7
0
    def __init__(self,
                 pb,
                 starred=False,
                 now=None,
                 num_stars=None,
                 membership_desc=None):
        super(ProjectView, self).__init__(pb)

        self.limited_summary = template_helpers.FitUnsafeText(
            pb.summary, self._MAX_SUMMARY_CHARS)

        self.limited_description = template_helpers.FitUnsafeText(
            pb.description, self._LIMITED_DESCRIPTION_CHARS)

        self.state_name = str(pb.state)  # Gives the enum name
        self.relative_home_url = '/p/%s' % pb.project_name

        if now is None:
            now = time.time()

        last_full_hour = now - (now % framework_constants.SECS_PER_HOUR)
        self.cached_content_timestamp = max(pb.cached_content_timestamp,
                                            last_full_hour)
        self.last_updated_exists = ezt.boolean(pb.recent_activity)
        course_grain, fine_grain = timestr.GetHumanScaleDate(
            pb.recent_activity)
        if course_grain == 'Older':
            self.recent_activity = fine_grain
        else:
            self.recent_activity = course_grain

        self.starred = ezt.boolean(starred)

        self.num_stars = num_stars
        self.plural = '' if num_stars == 1 else 's'
        self.membership_desc = membership_desc
Esempio n. 8
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
Esempio n. 9
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
Esempio n. 10
0
    def testFitTextMethods(self):
        """Tests both FitUnsafeText with an eye on i18n."""
        # pylint: disable=anomalous-unicode-escape-in-string
        test_data = (
            u'This is a short string.',
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. '
            u'This is a much longer string. ',

            # This is a short escaped i18n string
            '\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab'.decode('utf-8'),

            # This is a longer i18n string
            '\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
            '\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '
            '\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
            '\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '
            '\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
            '\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '
            '\xd5\xa1\xd5\xba\xd5\xa1\xd5\xaf\xd5\xab '
            '\xe6\x88\x91\xe8\x83\xbd\xe5\x90\x9e '.decode('utf-8'),

            # This is a longer i18n string that was causing trouble.
            '\u041d\u0430 \u0431\u0435\u0440\u0435\u0433\u0443'
            ' \u043f\u0443\u0441\u0442\u044b\u043d\u043d\u044b\u0445'
            ' \u0432\u043e\u043b\u043d \u0421\u0442\u043e\u044f\u043b'
            ' \u043e\u043d, \u0434\u0443\u043c'
            ' \u0432\u0435\u043b\u0438\u043a\u0438\u0445'
            ' \u043f\u043e\u043b\u043d, \u0418'
            ' \u0432\u0434\u0430\u043b\u044c'
            ' \u0433\u043b\u044f\u0434\u0435\u043b.'
            ' \u041f\u0440\u0435\u0434 \u043d\u0438\u043c'
            ' \u0448\u0438\u0440\u043e\u043a\u043e'
            ' \u0420\u0435\u043a\u0430'
            ' \u043d\u0435\u0441\u043b\u0430\u0441\u044f;'
            ' \u0431\u0435\u0434\u043d\u044b\u0439'
            ' \u0447\u0451\u043b\u043d \u041f\u043e'
            ' \u043d\u0435\u0439'
            ' \u0441\u0442\u0440\u0435\u043c\u0438\u043b\u0441\u044f'
            ' \u043e\u0434\u0438\u043d\u043e\u043a\u043e.'
            ' \u041f\u043e \u043c\u0448\u0438\u0441\u0442\u044b\u043c,'
            ' \u0442\u043e\u043f\u043a\u0438\u043c'
            ' \u0431\u0435\u0440\u0435\u0433\u0430\u043c'
            ' \u0427\u0435\u0440\u043d\u0435\u043b\u0438'
            ' \u0438\u0437\u0431\u044b \u0437\u0434\u0435\u0441\u044c'
            ' \u0438 \u0442\u0430\u043c, \u041f\u0440\u0438\u044e\u0442'
            ' \u0443\u0431\u043e\u0433\u043e\u0433\u043e'
            ' \u0447\u0443\u0445\u043e\u043d\u0446\u0430;'
            ' \u0418 \u043b\u0435\u0441,'
            ' \u043d\u0435\u0432\u0435\u0434\u043e\u043c\u044b\u0439'
            ' \u043b\u0443\u0447\u0430\u043c \u0412'
            ' \u0442\u0443\u043c\u0430\u043d\u0435'
            ' \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u043d\u043e'
            '\u0433\u043e \u0441\u043e\u043b\u043d\u0446\u0430,'
            ' \u041a\u0440\u0443\u0433\u043e\u043c'
            ' \u0448\u0443\u043c\u0435\u043b.'.decode('utf-8'))

        for unicode_s in test_data:
            # Get the length in characters, not bytes.
            length = len(unicode_s)

            # Test the FitUnsafeText method at the length boundary.
            fitted_unsafe_text = template_helpers.FitUnsafeText(
                unicode_s, length)
            self.assertEqual(fitted_unsafe_text, unicode_s)

            # Set some values that test FitString well.
            available_space = length / 2
            max_trailing = length / 4
            # Break the string at various places - symmetric range around 0
            for i in range(1 - max_trailing, max_trailing):
                # Test the FitUnsafeText method.
                fitted_unsafe_text = template_helpers.FitUnsafeText(
                    unicode_s, available_space - i)
                self.assertEqual(fitted_unsafe_text[:available_space - i],
                                 unicode_s[:available_space - i])

            # Test a string that is already unicode
            u_string = u'This is already unicode'
            fitted_unsafe_text = template_helpers.FitUnsafeText(u_string, 100)
            self.assertEqual(u_string, fitted_unsafe_text)

            # Test a string that is already unicode, and has non-ascii in it.
            u_string = u'This is already unicode este\\u0301tico'
            fitted_unsafe_text = template_helpers.FitUnsafeText(u_string, 100)
            self.assertEqual(u_string, fitted_unsafe_text)
Esempio n. 11
0
    def __init__(self, field_def, config, user_views=None, approval_def=None):
        super(FieldDefView, self).__init__(field_def)

        self.type_name = str(field_def.field_type)

        self.choices = []
        if field_def.field_type == tracker_pb2.FieldTypes.ENUM_TYPE:
            self.choices = tracker_helpers.LabelsMaskedByFields(
                config, [field_def.field_name], trim_prefix=True)

        self.approvers = []
        self.survey = ''
        self.survey_questions = []
        if (approval_def and field_def.field_type
                == tracker_pb2.FieldTypes.APPROVAL_TYPE):
            self.approvers = [
                user_views.get(approver_id)
                for approver_id in approval_def.approver_ids
            ]
            if approval_def.survey:
                self.survey = approval_def.survey
                self.survey_questions = self.survey.split('\n')

        self.docstring_short = template_helpers.FitUnsafeText(
            field_def.docstring, 200)
        self.validate_help = None

        if field_def.is_required:
            self.importance = 'required'
        elif field_def.is_niche:
            self.importance = 'niche'
        else:
            self.importance = 'normal'

        if field_def.min_value is not None:
            self.min_value = field_def.min_value
            self.validate_help = 'Value must be >= %d' % field_def.min_value
        else:
            self.min_value = None  # Otherwise it would default to 0

        if field_def.max_value is not None:
            self.max_value = field_def.max_value
            self.validate_help = 'Value must be <= %d' % field_def.max_value
        else:
            self.max_value = None  # Otherwise it would default to 0

        if field_def.min_value is not None and field_def.max_value is not None:
            self.validate_help = 'Value must be between %d and %d' % (
                field_def.min_value, field_def.max_value)

        if field_def.regex:
            self.validate_help = 'Value must match regex: %s' % field_def.regex

        if field_def.needs_member:
            self.validate_help = 'Value must be a project member'

        if field_def.needs_perm:
            self.validate_help = (
                'Value must be a project member with permission %s' %
                field_def.needs_perm)

        self.date_action_str = str(field_def.date_action
                                   or 'no_action').lower()

        self.admins = []
        if user_views:
            self.admins = [
                user_views.get(admin_id) for admin_id in field_def.admin_ids
            ]

        if field_def.approval_id:
            self.is_approval_subfield = ezt.boolean(True)
            self.parent_approval_name = tracker_bizobj.FindFieldDefByID(
                field_def.approval_id, config).field_name
        else:
            self.is_approval_subfield = ezt.boolean(False)

        self.is_phase_field = ezt.boolean(field_def.is_phase_field)