Exemplo n.º 1
0
    def drafts(self):
        """A list of change ids that have drafts by this user.

    This is cached in memcache.
    """
        if self._draft_key is None:
            self._draft_key = MemCacheKey(key='user_drafts:%s' % self.email,
                                          incore=True,
                                          timeout=3600)

        def query_store():
            # We're looking for the Change key id.
            # The ancestry of comments goes:
            # Change -> PatchSet -> Patch -> Comment.
            #
            change_ids = set(
                comment.key().parent().parent().parent().id()
                for comment in gql(Comment, 'WHERE author = :1'
                                   ' AND draft = TRUE', self.user))
            return list(change_ids)

        return self._draft_key.get(query_store)
Exemplo n.º 2
0
  def drafts(self):
    """A list of change ids that have drafts by this user.

    This is cached in memcache.
    """
    if self._draft_key is None:
      self._draft_key = MemCacheKey(
          key = 'user_drafts:%s' % self.email,
          incore = True,
          timeout = 3600)

    def query_store():
      # We're looking for the Change key id.
      # The ancestry of comments goes:
      # Change -> PatchSet -> Patch -> Comment.
      #
      change_ids = set(comment.key().parent().parent().parent().id()
                       for comment
                       in gql(Comment,
                              'WHERE author = :1'
                              ' AND draft = TRUE',
                              self.user))
      return list(change_ids)
    return self._draft_key.get(query_store)
Exemplo n.º 3
0
class Account(BackedUpModel):
  """Maps a user or email address to a user-selected real_name, and more.

  Nicknames do not have to be unique.

  The default real_name is generated from the email address by
  stripping the first '@' sign and everything after it.  The email
  should not be empty nor should it start with '@' (AssertionError
  error is raised if either of these happens).

  Holds a list of ids of starred changes.  The expectation
  that you won't have more than a dozen or so starred changes (a few
  hundred in extreme cases) and the memory used up by a list of
  integers of that size is very modest, so this is an efficient
  solution.  (If someone found a use case for having thousands of
  starred changes we'd have to think of a different approach.)

  Returns whether a user is authorized to do lgtm or verify.
  For now, these authorization check methods do not test which repository
  the change is in.  This will change.
  """

  user = db.UserProperty(required=True)
  email = db.EmailProperty(required=True)  # key == <email>
  preferred_email = db.EmailProperty()

  created = db.DateTimeProperty(auto_now_add=True)
  modified = db.DateTimeProperty(auto_now=True)

  is_admin = db.BooleanProperty(default=False)
  welcomed = db.BooleanProperty(default=False)
  real_name_entered = db.BooleanProperty(default=False)
  real_name = db.StringProperty()
  mailing_address = db.TextProperty()
  mailing_address_country = db.StringProperty()
  phone_number = db.StringProperty()
  fax_number = db.StringProperty()

  cla_verified = db.BooleanProperty(default=False)
  cla_verified_by = db.UserProperty()
  cla_verified_timestamp = db.DateTimeProperty() # the first time it's set
  individual_cla_version = db.IntegerProperty(default=IndividualCLA.NONE)
  individual_cla_timestamp = db.DateTimeProperty()
  cla_comments = db.TextProperty()

  default_context = db.IntegerProperty(default=DEFAULT_CONTEXT,
                                       choices=CONTEXT_CHOICES)
  stars = db.ListProperty(int)  # Change ids of all starred changes
  unclaimed_changes_projects = db.ListProperty(db.Key)

  # Current user's Account.  Updated by middleware.AddUserToRequestMiddleware.
  current_user_account = None

  def get_email(self):
    "Gets the email that this person wants us to use -- separate from login."
    if self.preferred_email:
      return self.preferred_email
    else:
      return self.email

  def get_email_formatted(self):
    return '"%s" <%s>' % (self.real_name, self.get_email())

  @classmethod
  def get_account_for_user(cls, user):
    """Get the Account for a user, creating a default one if needed."""
    email = user.email()
    assert email
    key = '<%s>' % email
    # Since usually the account already exists, first try getting it
    # without the transaction implied by get_or_insert().
    account = cls.get_by_key_name(key)
    if account is not None:
      return account
    real_name = user.nickname()
    if '@' in real_name:
      real_name = real_name.split('@', 1)[0]
    assert real_name
    return cls.get_or_insert(key, user=user, email=email, real_name=real_name)

  @classmethod
  def get_account_for_email(cls, email):
    """Get the Account for an email address, or return None."""
    assert email
    key = '<%s>' % email
    return cls.get_by_key_name(key)

  @classmethod
  def get_accounts_for_emails(cls, emails):
    """Get the Accounts for all email address.
    """
    return cls.get_by_key_name(map(lambda x: '<%s>' % x, emails))

  @classmethod
  def get_real_name_for_email(cls, email):
    """Get the real_name for an email address, possibly a default."""
    account = cls.get_account_for_email(email)
    if account is not None and account.real_name:
      return account.real_name
    real_name = email
    if '@' in real_name:
      real_name = real_name.split('@', 1)[0]
    assert real_name
    return real_name

  @classmethod
  def get_accounts_for_real_name(cls, real_name):
    """Get the list of Accounts that have this real_name."""
    assert real_name
    assert '@' not in real_name
    return list(gql(cls, 'WHERE real_name = :1', real_name))

  @classmethod
  def get_email_for_real_name(cls, real_name):
    """Turn a real_name into an email address.

    If the real_name is not unique or does not exist, this returns None.
    """
    accounts = cls.get_accounts_for_real_name(real_name)
    if len(accounts) != 1:
      return None
    return accounts[0].email

  _draft_key = None

  @property
  def drafts(self):
    """A list of change ids that have drafts by this user.

    This is cached in memcache.
    """
    if self._draft_key is None:
      self._draft_key = MemCacheKey(
          key = 'user_drafts:%s' % self.email,
          incore = True,
          timeout = 3600)

    def query_store():
      # We're looking for the Change key id.
      # The ancestry of comments goes:
      # Change -> PatchSet -> Patch -> Comment.
      #
      change_ids = set(comment.key().parent().parent().parent().id()
                       for comment
                       in gql(Comment,
                              'WHERE author = :1'
                              ' AND draft = TRUE',
                              self.user))
      return list(change_ids)
    return self._draft_key.get(query_store)

  def update_drafts(self, change, have_drafts=None):
    """Update the user's draft status for this change.

    Args:
      change: an Change instance.
      have_drafts: optional bool forcing the draft status.  By default,
          change.num_drafts is inspected (which may query the datastore).

    The Account is written to the datastore if necessary.
    """
    my_drafts = self.drafts
    id = change.key().id()
    if have_drafts is None:
      have_drafts = bool(change.num_drafts)  # this may do a query

    if have_drafts:
      if id not in my_drafts:
        my_drafts.append(id)
        self._draft_key.set(my_drafts)
    else:
      if id in my_drafts:
        my_drafts.remove(id)
        self._draft_key.set(my_drafts)
Exemplo n.º 4
0
class Account(BackedUpModel):
    """Maps a user or email address to a user-selected real_name, and more.

  Nicknames do not have to be unique.

  The default real_name is generated from the email address by
  stripping the first '@' sign and everything after it.  The email
  should not be empty nor should it start with '@' (AssertionError
  error is raised if either of these happens).

  Holds a list of ids of starred changes.  The expectation
  that you won't have more than a dozen or so starred changes (a few
  hundred in extreme cases) and the memory used up by a list of
  integers of that size is very modest, so this is an efficient
  solution.  (If someone found a use case for having thousands of
  starred changes we'd have to think of a different approach.)

  Returns whether a user is authorized to do lgtm or verify.
  For now, these authorization check methods do not test which repository
  the change is in.  This will change.
  """

    user = db.UserProperty(required=True)
    email = db.EmailProperty(required=True)  # key == <email>
    preferred_email = db.EmailProperty()

    created = db.DateTimeProperty(auto_now_add=True)
    modified = db.DateTimeProperty(auto_now=True)

    is_admin = db.BooleanProperty(default=False)
    welcomed = db.BooleanProperty(default=False)
    real_name_entered = db.BooleanProperty(default=False)
    real_name = db.StringProperty()
    mailing_address = db.TextProperty()
    mailing_address_country = db.StringProperty()
    phone_number = db.StringProperty()
    fax_number = db.StringProperty()

    cla_verified = db.BooleanProperty(default=False)
    cla_verified_by = db.UserProperty()
    cla_verified_timestamp = db.DateTimeProperty()  # the first time it's set
    individual_cla_version = db.IntegerProperty(default=IndividualCLA.NONE)
    individual_cla_timestamp = db.DateTimeProperty()
    cla_comments = db.TextProperty()

    default_context = db.IntegerProperty(default=DEFAULT_CONTEXT,
                                         choices=CONTEXT_CHOICES)
    stars = db.ListProperty(int)  # Change ids of all starred changes
    unclaimed_changes_projects = db.ListProperty(db.Key)

    # Current user's Account.  Updated by middleware.AddUserToRequestMiddleware.
    current_user_account = None

    def get_email(self):
        "Gets the email that this person wants us to use -- separate from login."
        if self.preferred_email:
            return self.preferred_email
        else:
            return self.email

    def get_email_formatted(self):
        return '"%s" <%s>' % (self.real_name, self.get_email())

    @classmethod
    def get_account_for_user(cls, user):
        """Get the Account for a user, creating a default one if needed."""
        email = user.email()
        assert email
        key = '<%s>' % email
        # Since usually the account already exists, first try getting it
        # without the transaction implied by get_or_insert().
        account = cls.get_by_key_name(key)
        if account is not None:
            return account
        real_name = user.nickname()
        if '@' in real_name:
            real_name = real_name.split('@', 1)[0]
        assert real_name
        return cls.get_or_insert(key,
                                 user=user,
                                 email=email,
                                 real_name=real_name)

    @classmethod
    def get_account_for_email(cls, email):
        """Get the Account for an email address, or return None."""
        assert email
        key = '<%s>' % email
        return cls.get_by_key_name(key)

    @classmethod
    def get_accounts_for_emails(cls, emails):
        """Get the Accounts for all email address.
    """
        return cls.get_by_key_name(map(lambda x: '<%s>' % x, emails))

    @classmethod
    def get_real_name_for_email(cls, email):
        """Get the real_name for an email address, possibly a default."""
        account = cls.get_account_for_email(email)
        if account is not None and account.real_name:
            return account.real_name
        real_name = email
        if '@' in real_name:
            real_name = real_name.split('@', 1)[0]
        assert real_name
        return real_name

    @classmethod
    def get_accounts_for_real_name(cls, real_name):
        """Get the list of Accounts that have this real_name."""
        assert real_name
        assert '@' not in real_name
        return list(gql(cls, 'WHERE real_name = :1', real_name))

    @classmethod
    def get_email_for_real_name(cls, real_name):
        """Turn a real_name into an email address.

    If the real_name is not unique or does not exist, this returns None.
    """
        accounts = cls.get_accounts_for_real_name(real_name)
        if len(accounts) != 1:
            return None
        return accounts[0].email

    _draft_key = None

    @property
    def drafts(self):
        """A list of change ids that have drafts by this user.

    This is cached in memcache.
    """
        if self._draft_key is None:
            self._draft_key = MemCacheKey(key='user_drafts:%s' % self.email,
                                          incore=True,
                                          timeout=3600)

        def query_store():
            # We're looking for the Change key id.
            # The ancestry of comments goes:
            # Change -> PatchSet -> Patch -> Comment.
            #
            change_ids = set(
                comment.key().parent().parent().parent().id()
                for comment in gql(Comment, 'WHERE author = :1'
                                   ' AND draft = TRUE', self.user))
            return list(change_ids)

        return self._draft_key.get(query_store)

    def update_drafts(self, change, have_drafts=None):
        """Update the user's draft status for this change.

    Args:
      change: an Change instance.
      have_drafts: optional bool forcing the draft status.  By default,
          change.num_drafts is inspected (which may query the datastore).

    The Account is written to the datastore if necessary.
    """
        my_drafts = self.drafts
        id = change.key().id()
        if have_drafts is None:
            have_drafts = bool(change.num_drafts)  # this may do a query

        if have_drafts:
            if id not in my_drafts:
                my_drafts.append(id)
                self._draft_key.set(my_drafts)
        else:
            if id in my_drafts:
                my_drafts.remove(id)
                self._draft_key.set(my_drafts)