def test_serialize(self): user_model = User( first_name="Foo", last_name="Bar", username="******", password="******", email=TEST_EMAIL, created_on=timezone.parse(DEFAULT_TIME), changed_on=timezone.parse(DEFAULT_TIME), ) self.session.add(user_model) self.session.commit() user = self.session.query(User).filter( User.email == TEST_EMAIL).first() deserialized_user = user_schema.dump(user) # No user_id and password in dump assert deserialized_user == { 'roles': [], 'created_on': DEFAULT_TIME, 'email': '*****@*****.**', 'changed_on': DEFAULT_TIME, 'active': None, 'last_login': None, 'last_name': 'Bar', 'fail_login_count': None, 'first_name': 'Foo', 'username': '******', 'login_count': None, }
def patch_user(username, update_mask=None): """Update a role""" try: data = user_schema.load(request.json) except ValidationError as e: raise BadRequest(detail=str(e.messages)) security_manager = current_app.appbuilder.sm user = security_manager.find_user(username=username) if user is None: detail = f"The User with username `{username}` was not found" raise NotFound(title="User not found", detail=detail) # Get fields to update. 'username' is always excluded (and it's an error to # include it in update_maek). if update_mask is not None: masked_data = {} missing_mask_names = [] for field in update_mask: field = field.strip() try: masked_data[field] = data[field] except KeyError: missing_mask_names.append(field) if missing_mask_names: detail = f"Unknown update masks: {', '.join(repr(n) for n in missing_mask_names)}" raise BadRequest(detail=detail) if "username" in masked_data: raise BadRequest("Cannot update fields: 'username'") data = masked_data else: data.pop("username", None) if "roles" in data: roles_to_update = [] missing_role_names = [] for role_data in data.pop("roles", ()): role_name = role_data["name"] role = security_manager.find_role(role_name) if role is None: missing_role_names.append(role_name) else: roles_to_update.append(role) if missing_role_names: detail = f"Unknown roles: {', '.join(repr(n) for n in missing_role_names)}" raise BadRequest(detail=detail) else: roles_to_update = None # Don't change existing value. if "password" in data: user.password = generate_password_hash(data.pop("password")) if roles_to_update is not None: user.roles = roles_to_update for key, value in data.items(): setattr(user, key, value) security_manager.update_user(user) return user_schema.dump(user)
def post_user(): """Create a new user""" try: data = user_schema.load(request.json) except ValidationError as e: raise BadRequest(detail=str(e.messages)) security_manager = current_app.appbuilder.sm username = data["username"] email = data["email"] if security_manager.find_user(username=username): detail = f"Username `{username}` already exists. Use PATCH to update." raise AlreadyExists(detail=detail) if security_manager.find_user(email=email): detail = f"The email `{email}` is already taken." raise AlreadyExists(detail=detail) roles_to_add = [] missing_role_names = [] for role_data in data.pop("roles", ()): role_name = role_data["name"] role = security_manager.find_role(role_name) if role is None: missing_role_names.append(role_name) else: roles_to_add.append(role) if missing_role_names: detail = f"Unknown roles: {', '.join(repr(n) for n in missing_role_names)}" raise BadRequest(detail=detail) if roles_to_add: default_role = roles_to_add.pop() else: # No roles provided, use the F.A.B's default registered user role. default_role = security_manager.find_role( security_manager.auth_user_registration_role) user = security_manager.add_user(role=default_role, **data) if not user: detail = f"Failed to add user `{username}`." return Unknown(detail=detail) if roles_to_add: user.roles.extend(roles_to_add) security_manager.update_user(user) return user_schema.dump(user)
def patch_user(*, username: str, update_mask: UpdateMask = None) -> APIResponse: """Update a user""" try: data = user_schema.load(request.json) except ValidationError as e: raise BadRequest(detail=str(e.messages)) security_manager = get_airflow_app().appbuilder.sm user = security_manager.find_user(username=username) if user is None: detail = f"The User with username `{username}` was not found" raise NotFound(title="User not found", detail=detail) # Check unique username new_username = data.get('username') if new_username and new_username != username: if security_manager.find_user(username=new_username): raise AlreadyExists( detail=f"The username `{new_username}` already exists") # Check unique email email = data.get('email') if email and email != user.email: if security_manager.find_user(email=email): raise AlreadyExists(detail=f"The email `{email}` already exists") # Get fields to update. if update_mask is not None: masked_data = {} missing_mask_names = [] for field in update_mask: field = field.strip() try: masked_data[field] = data[field] except KeyError: missing_mask_names.append(field) if missing_mask_names: detail = f"Unknown update masks: {', '.join(repr(n) for n in missing_mask_names)}" raise BadRequest(detail=detail) data = masked_data roles_to_update: Optional[List[Role]] if "roles" in data: roles_to_update = [] missing_role_names = [] for role_data in data.pop("roles", ()): role_name = role_data["name"] role = security_manager.find_role(role_name) if role is None: missing_role_names.append(role_name) else: roles_to_update.append(role) if missing_role_names: detail = f"Unknown roles: {', '.join(repr(n) for n in missing_role_names)}" raise BadRequest(detail=detail) else: roles_to_update = None # Don't change existing value. if "password" in data: user.password = generate_password_hash(data.pop("password")) if roles_to_update is not None: user.roles = roles_to_update for key, value in data.items(): setattr(user, key, value) security_manager.update_user(user) return user_schema.dump(user)