class RegisterView(MethodView): """View to register a new user.""" decorators = [user_already_authenticated] post_args = { "email": fields.Email(required=True, validate=[unique_user_email]), "password": fields.String( required=True, validate=[validate.Length(min=6, max=128)] ), } def login_user(self, user): """Perform any login actions.""" if ( not current_security.confirmable or current_security.login_without_confirmation ): after_this_request(_commit) login_user(user) def success_response(self, user): """Return a successful register response.""" return jsonify(default_user_payload(user)) @use_kwargs(post_args) def post(self, **kwargs): """Register a user.""" if not current_security.registerable: _abort(get_message("REGISTRATION_DISABLED")[0]) user = register_user(**kwargs) self.login_user(user) return self.success_response(user)
class EnrollmentListResource(Resource, EnrollmentBase): @use_kwargs({ "external_key": fields.Str(), "enrollment_type": fields.Str(), "state": fields.Str() }) @need_config_permission('OAREPO_ENROLLMENT_LIST_PERMISSION_FACTORY') def get(self, external_key=None, enrollment_type=None, state=None, **kwargs): if state: state = [x.strip() for x in state.split(',')] state = [Enrollment.ENROLLMENT_STATUS_CHOICES_REVERSE.get(s, s) for s in state if s] enrollments = Enrollment.list(external_key=external_key, enrollment_type=enrollment_type, state=state) query_filter = current_enrollments.list_permission_filter enrollments = query_filter(enrollments) pagination = Pagination(current_app, db) return pagination.paginate(enrollments, self.enrollment_fields, post_query_hook=lambda l: NeverEmptyList(l)) @need_config_permission('OAREPO_ENROLLMENT_ENROLL_PERMISSION_FACTORY') @use_args({ 'enrollment_type': fields.Str(), 'recipient': fields.Email(), 'email_template': fields.Str(), 'language': fields.Str(), 'mode': fields.Str(), 'external_key': fields.Str(), 'expiration_interval': fields.Int(), 'actions': fields.List(fields.Str()) }) def post(self, args): extra_data = {k: v for k, v in request.json.items() if k not in args} enrollment = enroll(**args, sender=current_user, extra_data=extra_data) return output_json(flask_restful.marshal(enrollment, self.enrollment_fields), 201)
class MongoHandler(BaseRequestHandler): mongo_handler_args = {'email': fields.Email(required=True)} def initialize(self): self.motor = self.application.motor self.db = self.motor.testing_db self.coll = self.db.testing_coll @gen.coroutine def get(self): reqargs = self.parse_request(self.mongo_handler_args) docs = yield self.coll.find_one({'email': reqargs['email']}) pprint.pprint(docs) if not docs: response = dict() else: response = dict(object_id=str(docs['_id']), email=docs['email']) self.write(response) self.finish() @gen.coroutine def post(self): reqargs = self.parse_request(self.mongo_handler_args) future = self.coll.insert({'email': reqargs['email']}) result = yield future response = dict(object_id=str(result)) self.write(response) self.finish()
class ResetPasswordToken(MethodResource): post_args = { 'email': fields.Email(required=True, description='User email address'), } @use_kwargs(post_args, locations=('json', 'form')) @use_kwargs_doc(post_args, locations=('json', 'form')) @doc(tags=['Authentication'], description='Send password reset email') def post(self, email): user = User.query.filter_by(email=email).first() message = 'If there is an account associated with this email address, a recovery email has been sent.' if not user: return {'message': message} token = security.ts.dumps(email, salt='recover-key') recover_url = _front_end_url + '/reset_password/{}'.format(token) data = { 'subject': 'Recover your account', 'user_id': user.id, 'username': user.first_name, 'email': user.email, 'recover_url': recover_url, } url = _email_api_url + '/user_notification/recover' r = rq.post(url, data=data) if r.status_code == 200: return {'message': message} else: abort(r.status_code)
class RHReportErrorAPI(RH): def _process_args(self): self.error_data = load_error_data(request.view_args['error_id']) if self.error_data is None: raise NotFound( 'Error details not found. We might be having some technical issues; please try again later.' ) def _save_report(self, email, comment): self._send_email(email, comment) if self.error_data['sentry_event_id'] is not None: submit_user_feedback(self.error_data, email, comment) def _send_email(self, email, comment): # using reply-to for the user email would be nicer, but email clients # usually only show the from address and it's nice to immediately see # whether an error report has an email address associated and if # multiple reports came from the same person template = get_template_module('core/emails/error_report.txt', comment=comment, error_data=self.error_data, server_name=url_parse( config.BASE_URL).netloc) send_email( make_email(config.SUPPORT_EMAIL, from_address=(email or config.NO_REPLY_EMAIL), template=template)) @use_kwargs({ 'email': fields.Email(missing=None), 'comment': fields.String(required=True), }) def _process(self, email, comment): self._save_report(email, comment) return '', 204
def test_parse_raises_validation_error_if_data_invalid(web_request, parser): args = { 'email': fields.Email(), } web_request.json = {'email': 'invalid'} with pytest.raises(ValidationError): parser.parse(args, web_request)
class SaveEmail(MethodResource): post_args = {**auth_args, **{ 'new_email': fields.Email(required=True, description='New email address'), }} @jwt_required @use_kwargs(post_args, locations=('json', 'form')) @use_kwargs_doc(post_args, locations=('json', 'form')) @doc(tags=['Account'], description='Save new email address') def post(self, password, otp_code, new_email): email = get_jwt_identity() user = User.query.filter_by(email=email).first() # Confirm OTP is correct if user.otp_complete: if not user.verify_totp(otp_code): message = 'Your second factor code was invalid.' abort(403, message=message) # Check password elif not user.verify_password(password): message = 'Incorrect password. Try again.' abort(403, message=message) # Check to make sure email address isn't already in use if User.query.filter_by(email=new_email).first(): message = 'Email address already in use. Please use another.' abort(403, message=message) # Commit new email address to database user.email = new_email user.save_to_db() return {'message': 'Email address was successfully changed.'}
def post_lead(): json = parser.parse({ 'email': fields.Email(required=True), 'first_name': fields.Str(required=False), }, request) lead = Lead.create(**json) return Response(lead).to_dict()
class Login(MethodResource): post_args = { 'email': fields.Email(required=True, description='User email address'), 'password': fields.Str(required=True, description='Password'), } @use_kwargs(post_args, locations=('json', 'form')) @use_kwargs_doc(post_args, locations=('json', 'form')) @doc(tags=['Authentication'], description='Login to account. Must post credentials in body.') def post(self, email, password): user = User.query.filter_by(email=email).first() print(user) if user is None: message = 'There is no account associated with this email address.' abort(401, message=message) elif not user.email_confirmed: abort(403, message=user.first_name) else: if user.verify_password(password): if user.otp_complete: user_id = user.id timestamp = int(time()) token = md5(('{}.{}.{}'.format(user_id, timestamp, SECRET)).encode()).hexdigest() print(token) second_factor = { 'user_id': user_id, 'timestamp': timestamp, 'token': token, 'role': user.role, } return {'second_factor': second_factor} else: ### Add back User 'roles' to differentiate access? return login_user(user) else: abort(401, message='Wrong credentials.')
class UserResource(Resource): @staticmethod def get_user(user_id): return EmailUser.query.get(user_id) def create_user(self, email): person = EmailUser(email_address=email) db.session.add(person) db.session.commit() return person def serialize_user(self, user): return user.email_address @use_kwargs( {'user_id': fields.Int(required=True, validate=user_must_exist_in_db)}, location='view_args') def get(self, user_id): user = EmailUser.query.get(user_id) return self.serialize_user(user) @use_kwargs({ 'email': fields.Email(required=True, validate=user_must_not_exist_in_db) }) def post(self, email): user = EmailUser(email_address=email) db.session.add(user) db.session.commit() return user.id @staticmethod def get_user(user_id): return EmailUser.query.get(user_id)
class RHUpdateRoom(RHRoomAdminBase): @use_args({ 'verbose_name': fields.Str(allow_none=True), 'site': fields.Str(allow_none=True), 'building': fields.String(validate=lambda x: x is not None), 'floor': fields.String(validate=lambda x: x is not None), 'number': fields.String(validate=lambda x: x is not None), 'longitude': fields.Float(allow_none=True), 'latitude': fields.Float(allow_none=True), 'is_reservable': fields.Bool(allow_none=True), 'reservations_need_confirmation': fields.Bool(allow_none=True), 'notification_emails': fields.List(fields.Email()), 'notification_before_days': fields.Int(validate=lambda x: 1 <= x <= 30, allow_none=True), 'notification_before_days_weekly': fields.Int(validate=lambda x: 1 <= x <= 30, allow_none=True), 'notification_before_days_monthly': fields.Int(validate=lambda x: 1 <= x <= 30, allow_none=True), 'notifications_enabled': fields.Bool(), 'end_notification_daily': fields.Int(validate=lambda x: 1 <= x <= 30, allow_none=True), 'end_notification_weekly': fields.Int(validate=lambda x: 1 <= x <= 30, allow_none=True), 'end_notification_monthly': fields.Int(validate=lambda x: 1 <= x <= 30, allow_none=True), 'end_notifications_enabled': fields.Bool(), 'booking_limit_days': fields.Int(validate=lambda x: x >= 1, allow_none=True), 'owner': Principal(validate=lambda x: x is not None, allow_none=True), 'key_location': fields.Str(), 'telephone': fields.Str(), 'capacity': fields.Int(validate=lambda x: x >= 1), 'division': fields.Str(allow_none=True), 'surface_area': fields.Int(validate=lambda x: x >= 0, allow_none=True), 'max_advance_days': fields.Int(validate=lambda x: x >= 1, allow_none=True), 'comments': fields.Str(), }) def _process(self, args): update_room(self.room, args) RHRoomsPermissions._jsonify_user_permissions.clear_cached(session.user) return jsonify(room_update_schema.dump(self.room, many=False))
def create_args(): """Defines and validates params for create""" return { "username": fields.String(required=True, validate=validate.Length(min=1)), "email": fields.Email(required=True), "password": fields.String(required=True), }
class UserInviteResponseSchema(Schema): id = fields.Int() email = fields.Email(required=True) token = fields.Str(required=True) expired_at = fields.DateTime(required=True) created_at = fields.DateTime(required=True) created_by_id = fields.Int(required=True)
class Register(MethodResource): post_args = { 'email': fields.Email(required=True, description='User email address'), 'password': fields.Str(required=True, description='Password'), 'username': fields.Str(required=False, description='Username') } @use_kwargs(post_args, locations=('json', 'form')) @use_kwargs_doc(post_args, locations=('json', 'form')) @doc(tags=['Authentication'], description='Register new account.') def post(self, email, password, username): # Check to see if email is already in use user = User.query.filter_by(email=email).first() if user: message = 'There is an account already associated with this email address.' abort(403, message=message) else: if username == missing: username = '******' cur = Currency.query.filter_by(symbol='USD').first() user = User( email=email, password=password, first_name=username, fiat_id=cur.id, # USD agreement=1, email_confirmed=1, btc_data=1 ) user.save_to_db() return {'message': 'User registered'}
class UserSchema(Schema): id = fields.Int(dump_only=True) email = fields.Email() password = fields.Str(load_only=True) if MARSHMALLOW_VERSION_INFO[0] < 3: class Meta: strict = True
class RHReportErrorAPI(RHReportErrorBase): @use_kwargs({ 'email': fields.Email(), 'comment': fields.String(required=True), }) def _process(self, email, comment): self._save_report(email, comment) return '', 204
class SignUpSchema(TwoPasswordsMixin, Schema): email = fields.Email(required=True, validate=validate.Length(max=128)) password_1 = fields.Str(required=True, validate=validate.Length(min=2, max=32)) password_2 = fields.Str(required=True, validate=validate.Length(min=2, max=32)) invite_token = fields.Str(required=True, validate=validate.Length(min=10, max=32))
class User(Resource): @use_kwargs({'email': fields.Email(required=True)}) def get(self, email): provider = Provider(client_id, client_secret, management_audience, domain) url = f'https://{domain}/api/v2/users-by-email' params = {'email': email} resp = provider.get(url, params) return resp.json()
def update_args(): """Defines and validates params for update""" return { "id": fields.UUID(required=True, load_from="id", location="view_args"), "username": fields.String(validate=validate.Length(min=1)), "email": fields.Email(), "password": fields.String(), "old_password": fields.String(), }
def post_login(): json = parser.parse( { 'email': fields.Email(required=True), 'password': fields.Str(required=True) }, request) user = User.query.filter_by(**json).first() if not user: raise ResponseException('Email or password is wrong', status=401) access_token = create_access_token(identity=user.email) return Response({'access_token': access_token}).to_dict()
class RHReportErrorAPI(RH): def _process_args(self): self.error_data = load_error_data(request.view_args['error_id']) if self.error_data is None: raise NotFound('Error details not found. We might be having some technical issues; please try again later.') def _save_report(self, email, comment): self._send_email(email, comment) if config.SENTRY_DSN and self.error_data['sentry_event_id'] is not None: self._send_sentry(email, comment) def _send_email(self, email, comment): # using reply-to for the user email would be nicer, but email clients # usually only show the from address and it's nice to immediately see # whether an error report has an email address associated and if # multiple reports came from the same person template = get_template_module('core/emails/error_report.txt', comment=comment, error_data=self.error_data, server_name=url_parse(config.BASE_URL).netloc) send_email(make_email(config.SUPPORT_EMAIL, from_address=(email or config.NO_REPLY_EMAIL), template=template)) def _send_sentry(self, email, comment): # strip password and query string from the DSN, and all auth data from the POST target dsn = re.sub(r':[^@/]+(?=@)', '', config.SENTRY_DSN) url = url_parse(dsn) dsn = unicode(url.replace(query=None)) verify = url.decode_query().get('ca_certs', True) url = unicode(url.replace(path='/api/embed/error-page/', netloc=url._split_netloc()[1], query=None)) user_data = self.error_data['request_info']['user'] or {'name': 'Anonymous', 'email': config.NO_REPLY_EMAIL} try: rv = requests.post(url, params={'dsn': dsn, 'eventId': self.error_data['sentry_event_id']}, data={'name': user_data['name'], 'email': email or user_data['email'], 'comments': comment}, headers={'Origin': config.BASE_URL}, verify=verify) rv.raise_for_status() except Exception: # don't bother users if this fails! Logger.get('sentry').exception('Could not submit user feedback') @use_kwargs({ 'email': fields.Email(missing=None), 'comment': fields.String(required=True), }) def _process(self, email, comment): self._save_report(email, comment) return '', 204
def build_schema(self, model): # Get the full list of parent classes from model to object classes = inspect.getmro(model) starting_point = False # Iterate in reversed order to start from object for c in reversed(classes): # Skip all parentes up to StructuredNode and StructuredRel (included) if not starting_point: # Found the starting point, next class will be descended up to model if c == StructuredNode or c == StructuredRel: starting_point = True # skip all parent up to StructuredNode and StructuredRel INCLUDED continue # Iterate all class attributes to find neomodel properties for attribute in c.__dict__: prop = getattr(c, attribute) if not isinstance(prop, properties.Property): continue # self.fields can be None when the special value * is given in input if self.fields and attribute not in self.fields: continue # log.info("Including property {}.{}", model.__name__, attribute) if isinstance(prop, properties.StringProperty): if prop.choices is None: self.declared_fields[attribute] = fields.Str() else: self.declared_fields[attribute] = Neo4jChoice( prop.choices) elif isinstance(prop, properties.BooleanProperty): self.declared_fields[attribute] = fields.Boolean() elif isinstance(prop, properties.IntegerProperty): self.declared_fields[attribute] = fields.Integer() elif isinstance(prop, properties.EmailProperty): self.declared_fields[attribute] = fields.Email() elif isinstance(prop, properties.DateTimeProperty): self.declared_fields[attribute] = fields.AwareDateTime() elif isinstance(prop, properties.UniqueIdProperty): self.declared_fields[attribute] = fields.Str() else: # pragma: no cover log.error( "Unsupport neomodel property: {}, fallback to StringProperty", prop.__class__.__name__, ) self.declared_fields[attribute] = fields.Str()
class Users(Resource): provider = Provider(client_id, client_secret, management_audience, domain) url = f'https://{domain}/api/v2/users' @use_kwargs({ 'email': fields.Email(required=True), 'password': fields.String(required=True) }) def post(self, email, password): data = {'email': email, 'password': password, 'connection': connection} resp = self.provider.post(self.url, data) return resp.json() def get(self): resp = self.provider.get(self.url) return resp.json() @use_kwargs({ 'email': fields.Email(required=True), }) def delete(self, email): resp = self.provider.get(f'https://{domain}/api/v2/users-by-email', {'email': email}) try: user = resp.json()[0] except IndexError: return custom_response(404, 'User not found.') try: user_id = user['user_id'] except KeyError: return custom_response(501, 'Failed to get user id.') resp = self.provider.delete(f'https://{domain}/api/v2/users/{user_id}') return custom_response(resp.status_code, 'User deleted.')
class OauthValidate(MethodResource): post_args = { 'email': fields.Email(required=True, description='User email address'), 'username': fields.Str(required=True, description='Username'), 'oauth_token': fields.Str(required=True, description='Oauth token'), 'provider': fields.Str(required=True, description='Oauth provider'), } @use_kwargs(post_args, locations=('json', 'form')) @use_kwargs_doc(post_args, locations=('json', 'form')) @doc(tags=['Authentication'], description='Oauth token validation endpoint') def post(self, email, username, oauth_token, provider): if provider == 'facebook': r = rq.get('https://graph.facebook.com/me', params={'access_token': oauth_token, 'fields': 'email'}) else: r = rq.get('https://auth-server.herokuapp.com/proxy', params={ 'path': 'https://api.twitter.com/1.1/account/verify_credentials.json?scope=email&include_email=true', 'access_token': oauth_token }) if r.status_code == 200: # If response is not the inputed email, someone is trying to hack into someone elses account if r.json()['email'] != email: return abort(401) user = User.query.filter_by(email=email).first() if not user: # Create new user user = User( password=oauth_token, first_name=username, email=email, email_confirmed=True, social_id=oauth_token, fiat_id=1, ) user.save_to_db() elif user.otp_complete: user_id = user.id timestamp = int(time()) token = md5(('{}.{}.{}'.format(user_id, timestamp, SECRET)).encode()).hexdigest() second_factor = { 'user_id': user_id, 'timestamp': timestamp, 'token': token, 'role': user.role, } return {'second_factor': second_factor} return login_user(user) else: abort(401)
class SendConfirmationEmailView(MethodView, UserViewMixin): """View function which sends confirmation instructions.""" decorators = [login_required] confirmation_link_func = default_confirmation_link_func post_args = { "email": fields.Email(required=True, validate=[user_exists]), } def verify(self, user): """Verify that user is not confirmed.""" if user.confirmed_at is not None: _abort(get_message("ALREADY_CONFIRMED")[0]) @classmethod def send_confirmation_link(cls, user): """Send confirmation link.""" send_email_enabled = current_security.confirmable and config_value( "SEND_REGISTER_EMAIL" ) if send_email_enabled: token, confirmation_link = cls.confirmation_link_func(user) send_mail( config_value("EMAIL_SUBJECT_REGISTER"), user.email, "confirmation_instructions", user=user, confirmation_link=confirmation_link, ) return token def success_response(self, user): """Return a successful confirmation email sent response.""" return jsonify( {"message": get_message("CONFIRMATION_REQUEST", email=user.email)[0]} ) @use_kwargs(post_args) def post(self, **kwargs): """Send confirmation email.""" user = self.get_user(**kwargs) self.verify(user) self.send_confirmation_link(user) return self.success_response(user)
class AuthSignupController(Resource): post_args = { "email": fields.Email(required=True), "password": fields.String(required=True), "login_provider": fields.Function( data_key="loginProvider", deserialize=lambda lp: UserLoginProviderType[lp], required=True, ), "first_name": fields.String(data_key="firstName"), "last_name": fields.String(data_key="lastName"), } @use_args(post_args, location="json") def post(self, args: Dict[str, Any]): new_user = auth_manager.signup_user( args["email"], login_provider=args["login_provider"], login_provider_uid=args["email"], login_provider_data=FlokLoginData(password=args["password"]), first_name=args.get("first_name"), last_name=args.get("last_name"), ) user_login_id = auth_manager.user_login_id(new_user) ### Auto creating company and retreat v1 upon signup for now. company_name = None if args.get("first_name"): company_name = f"{args.get('first_name')}'s company" new_company = company_manager.create_company(name=company_name, admins=[new_user]) retreat_manager.create_retreat(new_company, ) auth_manager.commit_changes() ### return responses.success( {"user": UserApiSchema.dump(obj=new_user)}, extra_headers=web.login_cookie_header(jwt, user_login_id.login_id), )
class Api(ViewsChallenge): __urls__ = [ "{}/api/payments/type/(?P<type_payment>[a-zA-Z0-9]+)/?".format( ViewsChallenge._version) ] __contract_default = { "client_id": fields.Int(required=True), "name_buyer": fields.Str(required=True, validate=validate_field_null), "email_buyer": fields.Email(required=True), "cpf_buyer": fields.Str(required=True, validate=validate_field_null), "amount": fields.Float(required=True), } __contract_boleto = copy.copy(__contract_default) __contract_card = copy.copy(__contract_default) __contract_card.update({ "card_name": fields.Str(required=True, validate=validate_field_null), "card_number": fields.Str(required=True, validate=validate_field_null), "card_expiration_date": fields.Str(required=True, validate=validate_field_null), "card_cvv": fields.Int(required=True, validate=validate_field_null), }) __type_paymends = {"card": __contract_card, "boleto": __contract_boleto} def __get_instance(self, p_type): """Return instance payment.""" return FactoryTypePayment.get_instance(p_type) def __get_param_parser(self, p_type): if p_type not in self.__type_paymends.keys(): raise TypePaymentNotFound("Payment not found %s" % p_type) return parser.parse(self.__type_paymends[p_type], self.request) async def post(self, type_payment): """Post to create payment.""" try: param = self.__get_param_parser(type_payment) instance = self.__get_instance(type_payment) await self._execute_method(instance.create, param) except ERRORS_CHALLENGE as error: logger.exception(str(error)) self.error(400, str(error))
class RoleUserListResource(TokenRequiredResource): get_args = { "name": fields.String(allow_none=True, validate=lambda x: 0 <= len(x) <= 255), "email": fields.Email(allow_none=True, validate=validate.Email()), "location": fields.String(allow_none=True, validate=lambda x: 0 <= len(x) <= 255), "confirmed": fields.Boolean(), "created_at": fields.DateTime(allow_none=True, format="iso8601"), } @admin_required @use_args(get_args) def get(self, query_args, id): filters = [User.role_id == id] if "name" in query_args: filters.append( User.name.like("%{filter}%".format(filter=query_args["name"]))) if "email" in query_args: filters.append( User.email.like( "%{filter}%".format(filter=query_args["email"]))) if "location" in query_args: filters.append( User.location.like( "%{filter}%".format(filter=query_args["location"]))) if "confirmed" in query_args: filters.append(User.confirmed == query_args["confirmed"]) if "created_at" in query_args: filters.append(User.created_at == query_args["created_at"]) pagination_helper = PaginationHelper( request, query=User.query.filter(*filters), resource_for_url="api.role_users", key_name="results", schema=user_schema, url_parameters={"id": id}, ) result = pagination_helper.paginate_query() return result
class UserSubscriptionController(Resource): post_args = {"from_address": fields.Email(data_key="fromAddress", required=True)} @jwt.requires_auth @use_args(post_args, location="json") def post(self, args: dict): from_address = args["from_address"] existing_subscription = content_manager.get_subscription_by_from_address( from_address ) if existing_subscription: subscription = existing_subscription else: subscription = content_manager.create_subscription(from_address) if not subscription: return responses.error("Something went wrong", 500) new_user_subscription = user_manager.add_user_subscription(g.user, subscription) user_manager.commit_changes() return responses.success("Success")
class ForgotPasswordView(MethodView, UserViewMixin): """View to get a link to reset the user password.""" decorators = [user_already_authenticated] reset_password_link_func = default_reset_password_link_func post_args = { "email": fields.Email(required=True, validate=[user_exists]), } @classmethod def send_reset_password_instructions(cls, user): """Send email containing instructions to reset password.""" token, reset_link = cls.reset_password_link_func(user) if config_value("SEND_PASSWORD_RESET_EMAIL"): send_mail( config_value("EMAIL_SUBJECT_PASSWORD_RESET"), user.email, "reset_instructions", user=user, reset_link=reset_link, ) reset_password_instructions_sent.send( current_app._get_current_object(), user=user, token=token ) def success_response(self, user): """Return a response containing reset password instructions.""" return jsonify( {"message": get_message("PASSWORD_RESET_REQUEST", email=user.email)[0]} ) @use_kwargs(post_args) def post(self, **kwargs): """Send reset password instructions.""" if not current_security.recoverable: _abort(get_message("PASSWORD_RECOVERY_DISABLED")[0]) user = self.get_user(**kwargs) self.send_reset_password_instructions(user) return self.success_response(user)