Beispiel #1
0
 def testGetHostPort_BrandedDomain(self):
     """A prod server can have a preferred domain."""
     self.assertEqual('example.com', framework_helpers.GetHostPort())
     self.assertEqual('branded.com',
                      framework_helpers.GetHostPort(project_name='proj'))
     self.assertEqual(
         'unbranded.com',
         framework_helpers.GetHostPort(project_name='other-proj'))
Beispiel #2
0
    def HandleRequest(self, mr):
        """Process the task to process an issue date action.

    Args:
      mr: common information parsed from the HTTP request.

    Returns:
      Results dictionary in JSON format which is useful just for debugging.
      The main goal is the side-effect of sending emails.
    """
        issue_id = mr.GetPositiveIntParam('issue_id')
        hostport = framework_helpers.GetHostPort()
        issue = self.services.issue.GetIssue(mr.cnxn, issue_id)
        project = self.services.project.GetProject(mr.cnxn, issue.project_id)
        config = self.services.config.GetProjectConfig(mr.cnxn,
                                                       issue.project_id)
        pings = self._CalculateIssuePings(issue, config)
        if not pings:
            logging.warning('Issue %r has no dates to ping afterall?',
                            issue_id)
            return
        comment = self._CreatePingComment(mr.cnxn, issue, pings, hostport)

        users_by_id = framework_views.MakeAllUserViews(
            mr.cnxn, self.services.user,
            tracker_bizobj.UsersInvolvedInIssues([issue]), [comment.user_id])
        logging.info('users_by_id is %r', users_by_id)
        tasks = self._MakeEmailTasks(mr.cnxn, issue, project, config, comment,
                                     hostport, users_by_id, pings)

        notified = notify_helpers.AddAllEmailTasks(tasks)
        return {
            'notified': notified,
        }
Beispiel #3
0
def convert_person(user_id, cnxn, services, trap_exception=False):
    """Convert user id to API AtomPerson PB or None if user_id is None."""

    if not user_id:
        # convert_person should handle 'converting' optional user values,
        # like issue.owner, where user_id may be None.
        return None
    if user_id == framework_constants.DELETED_USER_ID:
        return api_pb2_v1.AtomPerson(
            kind='monorail#issuePerson',
            name=framework_constants.DELETED_USER_NAME)
    try:
        user = services.user.GetUser(cnxn, user_id)
    except exceptions.NoSuchUserException as ex:
        if trap_exception:
            logging.warning(str(ex))
            return None
        else:
            raise ex

    days_ago = None
    if user.last_visit_timestamp:
        secs_ago = int(time.time()) - user.last_visit_timestamp
        days_ago = secs_ago // framework_constants.SECS_PER_DAY
    return api_pb2_v1.AtomPerson(kind='monorail#issuePerson',
                                 name=user.email,
                                 htmlLink='https://%s/u/%d' %
                                 (framework_helpers.GetHostPort(), user_id),
                                 last_visit_days_ago=days_ago,
                                 email_bouncing=bool(
                                     user.email_bounce_timestamp),
                                 vacation_message=user.vacation_message)
def convert_person(user_id, cnxn, services, trap_exception=False):
  """Convert user id to API AtomPerson PB."""

  if not user_id:
    return None
  try:
    user = services.user.GetUser(cnxn, user_id)
  except user_svc.NoSuchUserException as ex:
    if trap_exception:
      logging.warning(str(ex))
      return None
    else:
      raise ex

  days_ago = None
  if user.last_visit_timestamp:
    secs_ago = int(time.time()) - user.last_visit_timestamp
    days_ago = secs_ago / framework_constants.SECS_PER_DAY
  return api_pb2_v1.AtomPerson(
      kind='monorail#issuePerson',
      name=user.email,
      htmlLink='https://%s/u/%d' % (framework_helpers.GetHostPort(), user_id),
      last_visit_days_ago=days_ago,
      email_bouncing=bool(user.email_bounce_timestamp),
      vacation_message=user.vacation_message)
 def __init__(self):
   self.parser = commands.AssignmentParser(None)
   self.description = ''
   self.inbound_message = None
   self.commenter_id = None
   self.project = None
   self.config = None
   self.hostport = framework_helpers.GetHostPort()
Beispiel #6
0
  def issues_insert(self, request):
    """Add a new issue."""
    mar = self.mar_factory(request)
    if not mar.perms.CanUsePerm(
        permissions.CREATE_ISSUE, mar.auth.effective_ids, mar.project, []):
      raise permissions.PermissionException(
          'The requester %s is not allowed to create issues for project %s.' %
          (mar.auth.email, mar.project_name))

    owner_id = None
    if request.owner:
      try:
        owner_id = self._services.user.LookupUserID(
            mar.cnxn, request.owner.name)
      except user_svc.NoSuchUserException:
        raise endpoints.BadRequestException(
            'The specified owner %s does not exist.' % request.owner.name)

    cc_ids = []
    if request.cc:
      cc_ids = self._services.user.LookupUserIDs(
          mar.cnxn, [ap.name for ap in request.cc],
          autocreate=True).values()
    comp_ids = api_pb2_v1_helpers.convert_component_ids(
        mar.config, request.components)
    fields_add, _, _, fields_labels, _ = (
        api_pb2_v1_helpers.convert_field_values(
            request.fieldValues, mar, self._services))
    field_helpers.ValidateCustomFields(
        mar, self._services, fields_add, mar.config, mar.errors)
    if mar.errors.AnyErrors():
      raise endpoints.BadRequestException(
          'Invalid field values: %s' % mar.errors.custom_fields)

    local_id = self._services.issue.CreateIssue(
        mar.cnxn, self._services, mar.project_id,
        request.summary, request.status, owner_id,
        cc_ids, request.labels + fields_labels, fields_add,
        comp_ids, mar.auth.user_id, request.description,
        blocked_on=api_pb2_v1_helpers.convert_issueref_pbs(
            request.blockedOn, mar, self._services),
        blocking=api_pb2_v1_helpers.convert_issueref_pbs(
            request.blocking, mar, self._services))
    new_issue = self._services.issue.GetIssueByLocalID(
        mar.cnxn, mar.project_id, local_id)

    self._services.issue_star.SetStar(
        mar.cnxn, self._services, mar.config, new_issue.issue_id,
        mar.auth.user_id, True)

    if request.sendEmail:
      notify.PrepareAndSendIssueChangeNotification(
          new_issue.issue_id, framework_helpers.GetHostPort(),
          new_issue.reporter_id, 0)

    return api_pb2_v1_helpers.convert_issue(
        api_pb2_v1.IssuesGetInsertResponse, new_issue, mar, self._services)
Beispiel #7
0
  def issues_comments_insert(self, request):
    """Add a comment."""
    mar = self.mar_factory(request)
    issue = self._services.issue.GetIssueByLocalID(
        mar.cnxn, mar.project_id, request.issueId)
    old_owner_id = tracker_bizobj.GetOwnerId(issue)
    if not permissions.CanCommentIssue(
        mar.auth.effective_ids, mar.perms, mar.project, issue,
        mar.granted_perms):
      raise permissions.PermissionException(
          'User is not allowed to comment this issue (%s, %d)' %
          (request.projectId, request.issueId))

    updates_dict = {}
    if request.updates:
      if request.updates.moveToProject:
        move_to = request.updates.moveToProject.lower()
        move_to_project = issuedetail.CheckMoveIssueRequest(
            self._services, mar, issue, True, move_to, mar.errors)
        if mar.errors.AnyErrors():
          raise endpoints.BadRequestException(mar.errors.move_to)
        updates_dict['move_to_project'] = move_to_project

      updates_dict['summary'] = request.updates.summary
      updates_dict['status'] = request.updates.status
      if request.updates.owner:
        if request.updates.owner == framework_constants.NO_USER_NAME:
          updates_dict['owner'] = framework_constants.NO_USER_SPECIFIED
        else:
          updates_dict['owner'] = self._services.user.LookupUserID(
              mar.cnxn, request.updates.owner)
      updates_dict['cc_add'], updates_dict['cc_remove'] = (
          api_pb2_v1_helpers.split_remove_add(request.updates.cc))
      updates_dict['cc_add'] = self._services.user.LookupUserIDs(
          mar.cnxn, updates_dict['cc_add'], autocreate=True).values()
      updates_dict['cc_remove'] = self._services.user.LookupUserIDs(
          mar.cnxn, updates_dict['cc_remove']).values()
      updates_dict['labels_add'], updates_dict['labels_remove'] = (
          api_pb2_v1_helpers.split_remove_add(request.updates.labels))
      blocked_on_add_strs, blocked_on_remove_strs = (
          api_pb2_v1_helpers.split_remove_add(request.updates.blockedOn))
      updates_dict['blocked_on_add'] = api_pb2_v1_helpers.issue_global_ids(
          blocked_on_add_strs, issue.project_id, mar,
          self._services)
      updates_dict['blocked_on_remove'] = api_pb2_v1_helpers.issue_global_ids(
          blocked_on_remove_strs, issue.project_id, mar,
          self._services)
      blocking_add_strs, blocking_remove_strs = (
          api_pb2_v1_helpers.split_remove_add(request.updates.blocking))
      updates_dict['blocking_add'] = api_pb2_v1_helpers.issue_global_ids(
          blocking_add_strs, issue.project_id, mar,
          self._services)
      updates_dict['blocking_remove'] = api_pb2_v1_helpers.issue_global_ids(
          blocking_remove_strs, issue.project_id, mar,
          self._services)
      components_add_strs, components_remove_strs = (
          api_pb2_v1_helpers.split_remove_add(request.updates.components))
      updates_dict['components_add'] = (
          api_pb2_v1_helpers.convert_component_ids(
              mar.config, components_add_strs))
      updates_dict['components_remove'] = (
          api_pb2_v1_helpers.convert_component_ids(
              mar.config, components_remove_strs))
      if request.updates.mergedInto:
        merge_project_name, merge_local_id = tracker_bizobj.ParseIssueRef(
            request.updates.mergedInto)
        merge_into_project = self._services.project.GetProjectByName(
            mar.cnxn, merge_project_name or issue.project_name)
        merge_into_issue = self._services.issue.GetIssueByLocalID(
            mar.cnxn, merge_into_project.project_id, merge_local_id)
        merge_allowed = tracker_helpers.IsMergeAllowed(
            merge_into_issue, mar, self._services)
        if not merge_allowed:
          raise permissions.PermissionException(
            'User is not allowed to merge into issue %s:%s' %
            (merge_into_issue.project_name, merge_into_issue.local_id))
        updates_dict['merged_into'] = merge_into_issue.issue_id
      (updates_dict['field_vals_add'], updates_dict['field_vals_remove'],
       updates_dict['fields_clear'], updates_dict['fields_labels_add'],
       updates_dict['fields_labels_remove']) = (
          api_pb2_v1_helpers.convert_field_values(
              request.updates.fieldValues, mar, self._services))

    field_helpers.ValidateCustomFields(
        mar, self._services,
        (updates_dict.get('field_vals_add', []) +
         updates_dict.get('field_vals_remove', [])),
        mar.config, mar.errors)
    if mar.errors.AnyErrors():
      raise endpoints.BadRequestException(
          'Invalid field values: %s' % mar.errors.custom_fields)

    _, comment = self._services.issue.DeltaUpdateIssue(
        cnxn=mar.cnxn, services=self._services,
        reporter_id=mar.auth.user_id,
        project_id=mar.project_id, config=mar.config, issue=issue,
        status=updates_dict.get('status'), owner_id=updates_dict.get('owner'),
        cc_add=updates_dict.get('cc_add', []),
        cc_remove=updates_dict.get('cc_remove', []),
        comp_ids_add=updates_dict.get('components_add', []),
        comp_ids_remove=updates_dict.get('components_remove', []),
        labels_add=(updates_dict.get('labels_add', []) +
                    updates_dict.get('fields_labels_add', [])),
        labels_remove=(updates_dict.get('labels_remove', []) +
                       updates_dict.get('fields_labels_remove', [])),
        field_vals_add=updates_dict.get('field_vals_add', []),
        field_vals_remove=updates_dict.get('field_vals_remove', []),
        fields_clear=updates_dict.get('fields_clear', []),
        blocked_on_add=updates_dict.get('blocked_on_add', []),
        blocked_on_remove=updates_dict.get('blocked_on_remove', []),
        blocking_add=updates_dict.get('blocking_add', []),
        blocking_remove=updates_dict.get('blocking_remove', []),
        merged_into=updates_dict.get('merged_into'),
        index_now=False,
        comment=request.content,
        summary=updates_dict.get('summary'),
    )

    move_comment = None
    if 'move_to_project' in updates_dict:
      move_to_project = updates_dict['move_to_project']
      old_text_ref = 'issue %s:%s' % (issue.project_name, issue.local_id)
      tracker_fulltext.UnindexIssues([issue.issue_id])
      moved_back_iids = self._services.issue.MoveIssues(
          mar.cnxn, move_to_project, [issue], self._services.user)
      new_text_ref = 'issue %s:%s' % (issue.project_name, issue.local_id)
      if issue.issue_id in moved_back_iids:
        content = 'Moved %s back to %s again.' % (old_text_ref, new_text_ref)
      else:
        content = 'Moved %s to now be %s.' % (old_text_ref, new_text_ref)
      move_comment = self._services.issue.CreateIssueComment(
        mar.cnxn, move_to_project.project_id, issue.local_id, mar.auth.user_id,
        content, amendments=[
            tracker_bizobj.MakeProjectAmendment(move_to_project.project_name)])

    if 'merged_into' in updates_dict:
      new_starrers = tracker_helpers.GetNewIssueStarrers(
          mar.cnxn, self._services, issue.issue_id, merge_into_issue.issue_id)
      tracker_helpers.AddIssueStarrers(
          mar.cnxn, self._services, mar,
          merge_into_issue.issue_id, merge_into_project, new_starrers)
      _merge_comment = tracker_helpers.MergeCCsAndAddComment(
        self._services, mar, issue, merge_into_project, merge_into_issue)
      merge_into_issue_cmnts = self._services.issue.GetCommentsForIssue(
          mar.cnxn, merge_into_issue.issue_id)
      notify.PrepareAndSendIssueChangeNotification(
          merge_into_issue.issue_id, framework_helpers.GetHostPort(),
          mar.auth.user_id, len(merge_into_issue_cmnts) - 1, send_email=True)

    tracker_fulltext.IndexIssues(
        mar.cnxn, [issue], self._services.user, self._services.issue,
        self._services.config)

    comment = comment or move_comment
    if comment is None:
      return api_pb2_v1.IssuesCommentsInsertResponse()

    cmnts = self._services.issue.GetCommentsForIssue(mar.cnxn, issue.issue_id)
    seq = len(cmnts) - 1

    if request.sendEmail:
      notify.PrepareAndSendIssueChangeNotification(
          issue.issue_id, framework_helpers.GetHostPort(),
          comment.user_id, seq, send_email=True, old_owner_id=old_owner_id)

    can_delete = permissions.CanDelete(
      mar.auth.user_id, mar.auth.effective_ids, mar.perms,
      comment.deleted_by, comment.user_id, mar.project,
      permissions.GetRestrictions(issue), granted_perms=mar.granted_perms)
    return api_pb2_v1.IssuesCommentsInsertResponse(
        id=seq,
        kind='monorail#issueComment',
        author=api_pb2_v1_helpers.convert_person(
            comment.user_id, mar.cnxn, self._services),
        content=comment.content,
        published=datetime.datetime.fromtimestamp(comment.timestamp),
        updates=api_pb2_v1_helpers.convert_amendments(
            issue, comment.amendments, mar, self._services),
        canDelete=can_delete)
Beispiel #8
0
 def testGetHostPort_Local(self):
     """We use testing-app.appspot.com when running locally."""
     self.assertEqual('testing-app.appspot.com',
                      framework_helpers.GetHostPort())
     self.assertEqual('testing-app.appspot.com',
                      framework_helpers.GetHostPort(project_name='proj'))