def signup(self, require_activation=True, **kwargs): """ Create a new user. If *require_activation* is ``True``, the user will be flagged as requiring activation and an activation email will be sent. :param require_activation: The name to use. :type require_activation: bool. :param identities: A list of dictionaries representing identities to add to the new user. Each dictionary will be passed as keyword args to :py:class:`h.models.UserIdentity`. Remaining keyword arguments are used to construct a new :py:class:`h.models.User` object. :returns: the newly-created user object. :rtype: h.models.User """ kwargs.setdefault('authority', self.default_authority) # We extract any passed password as we use that separately to set the # user's password. password = kwargs.pop('password', None) # Extract any passed identities for this new user identities = kwargs.pop('identities', []) user = User(**kwargs) # Add identity relations to this new user, if provided user.identities = [ UserIdentity(user=user, **i_args) for i_args in identities ] self.session.add(user) if password is not None: self.password_service.update_password(user, password) # Create a new activation for the user if require_activation: self._require_activation(user) # FIXME: this is horrible, but is needed until the # notification/subscription system is made opt-out rather than opt-in # (at least from the perspective of the database). sub = Subscriptions(uri=user.userid, type='reply', active=True) self.session.add(sub) # Record a registration with the stats service if self.stats is not None: self.stats.incr('auth.local.register') return user
def signup(self, require_activation=True, **kwargs): """ Create a new user. If *require_activation* is ``True``, the user will be flagged as requiring activation and an activation email will be sent. :param require_activation: The name to use. :type require_activation: bool. Remaining keyword arguments are used to construct a new :py:class:`h.models.User` object. * *identities* A list of dictionaries representing identities to add to the new user. Each dictionary will be passed as keyword args to `h.models.UserIdentity`. :returns: the newly-created user object. :rtype: h.models.User """ kwargs.setdefault("authority", self.default_authority) # We extract any passed password as we use that separately to set the # user's password. password = kwargs.pop("password", None) # Extract any passed identities for this new user identities = kwargs.pop("identities", []) user = User(**kwargs) # Add identity relations to this new user, if provided user.identities = [ UserIdentity(user=user, **i_args) for i_args in identities ] self.session.add(user) if password is not None: self.password_service.update_password(user, password) # Create a new activation for the user if require_activation: try: self._require_activation(user) except IntegrityError as err: # When identical signup requests get issued at nearly the same time, they # race each other to the database and result in unique contraint integrity # errors on the user's email or username within the authority. if ('duplicate key value violates unique constraint "uq__user__email"' in err.args[0] or 'duplicate key value violates unique constraint "ix__user__userid"' in err.args[0]): log.warning( "concurrent account signup conflict error occurred during user signup %s", err.args[0], ) raise ConflictError( "The email address {} has already been registered.". format(user.email)) from err # If the exception is not related to the email or username, re-raise it. raise # FIXME: this is horrible, but is needed until the # notification/subscription system is made opt-out rather than opt-in # (at least from the perspective of the database). sub = Subscriptions(uri=user.userid, type="reply", active=True) self.session.add(sub) return user