def register(self, user: UserModel) -> UserModel: """ Registers a new user. If the user cannot register, because the login or the the ameil are already in use, a `ConstraintViolation` exception is raised. The student role is added automaticall to the new user. :param UserModel user: The userdate for the new user. """ data = user.json() url = self.url_for("/user/register/") result = self.requests.post(url, data=data) # Status 201: Ressource created if result.status_code == 201: response_data = result.json() user = UserModel.raw(response_data["user"]) bearer_token_data = BearerTokenData.parse_obj(response_data["bearer_token_data"]) # Not get the student role student_role = self.client.role_service.get_by_name_or_none( bearer_token_data.bearer_token, "student" ) if student_role: self.add_role(bearer_token_data.bearer_token, user, student_role) return ( user, bearer_token_data, ) raise DigiCubeError(f"Something went wrong. Status {result.status_code}")
def get(self, token, user_id: int, fields: XFieldList = None) -> Optional[UserModel]: """ Get a single user with the given id. :param str token: The authentification token. :param int user_id: The id of the requested user. :param XFieldList fields: The fields of the user, that should be returned. :return: The requested user. :rtype: :class:`UserModel` :raises InsufficientRights: If the requesting user has not the permission. :raises DoesNotExist: if no user exists with the provided login. :raises TokenExpired: is the token has expired. :raises ServerError: if an unpredicted exception occurred. """ # user = self.cache.get_user(user_id) # if user is not None: # logger.info("Cache hit for user %s", user.login) # return user # Cache hit # Cache miss headers = self.create_default_header(token, fields=fields) url = self.url_for(f"/user/{user_id}") response = self.requests.get(url, headers=headers) self.check_response_status(response, expected_status=200) user = UserModel.parse_obj(response.json()) # self.cache.set_user(user) # Cache the fetched user. return user
def get_all(): """The user list route.""" user_list = digicubes.user.all(digicubes.token) if requested_html(): return render_template("admin/users.jinja", users=user_list, token=digicubes.token) return UserModel.list_model(user_list).json()
def update(self, token, user: UserModelUpsert) -> UserModel: """ Update an existing user. If successfull, a new user model is returned with the latest version of the user data. """ response = self.requests.put( self.url_for(f"/user/{user.id}"), data=user.json(), headers=self.create_default_header(token), ) if response.status_code == 404: raise DoesNotExist(response.text) if response.status_code == 500: raise ServerError(response.text) if response.status_code != 200: raise ServerError(f"Wrong status. Expected 200. Got {response.status_code}") user = UserModel.parse_obj(response.json()) # Add or update the cached user # self.cache.set_user(user) return user # TODO Check other status_codes
def create(self, token: str, user: UserModelUpsert, fields: XFieldList = None) -> UserModel: """ Creates a new user """ headers = self.create_default_header(token, fields=fields) data = user.json() url = self.url_for("/users/") result = self.requests.post(url, data=data, headers=headers) if result.status_code == 201: # User created successfully. We cannot create the user directly # with the password, so we have to set the password in a second step. # # TODO: Why not able to set the password directly in the # REST call? Check is and change it, if possible. user_model = UserModel.parse_obj(result.json()) if not user.password: logger.debug("Created user without password.") else: self.set_password(token=token, user_id=user_model.id, new_password=user.password) return user_model if result.status_code == 409: raise ConstraintViolation(result.text) if result.status_code == 500: raise ServerError(result.text) raise ServerError(f"Unknown error. [{result.status_code}] {result.text}")
def get_school_teacher(self, token: str, school_id: int) -> List[UserModel]: headers = self.create_default_header(token) url = self.url_for(f"/school/{school_id}/teacher/") response = self.requests.get(url, headers=headers) self.check_response_status(response, expected_status=200) return [UserModel.parse_obj(user) for user in response.json()]
def update(user_id: int): """ Route to update an existing user. """ service: srv.UserService = digicubes.user token = digicubes.token form = UserForm() user_model: UserModel = None if form.is_submitted(): if form.validate({"login": [UserLoginAvailable(user_id=user_id)]}): user_model = UserModel.parse_obj(form.data) user_model.id = user_id digicubes.user.update(token, user_model) return redirect(url_for("user.get", user_id=user_id)) else: user_model: UserModel = service.get(token, user_id) else: user_model: UserModel = service.get(token, user_id) form.process(obj=user_model) return render_template( "admin/update_user.jinja", form=form, user=user_model, action=url_for("user.update", user_id=user_id), )
def get_my_schools(): """ Gets alls schools related to this user. The user must be a headmaster. If no schools are associated with this user, a info message will be displayed. """ school_service: SchoolService = digicubes.school schools = school_service.get_headmaster_schools(digicubes.token, UserModel(id=current_user.id)) return render_template("headmaster/schools.jinja", schools=schools)
def rfc_user_toggle_role(data: DataType) -> RfcResponse: user_id = data.get("user_id", None) role_id = data.get("role_id", None) operation = data.get("operation", "toggle") assert user_id is not None, "No user id provided" assert role_id is not None, "No role id provided" if operation == "add": server.user.add_role( server.token, UserModel(id=user_id), RoleModel(id=role_id, name="xxx") ) return RfcResponse(data={"user_id": user_id, "role_id": role_id, "has_role": True}) if operation == "remove": server.user.remove_role( server.token, UserModel(id=user_id), RoleModel(id=role_id, name="xxx") ) return RfcResponse(data={"user_id": user_id, "role_id": role_id, "has_role": False}) raise ValueError(f"Unknown or unsupported operation '{operation}'")
def school_remove_teacher(school_id: int, teacher_id: int): try: success = server.school.remove_teacher(server.token, SchoolModel(id=school_id), UserModel(id=teacher_id)) if success: flash("Teacher removed") else: flash("Could not remove teacher.") return redirect(url_for("school.get", school_id=school_id)) except Exception: logger.exception("Could not remove teacher from school") return redirect(url_for("school.get", school_id=school_id))
def delete(self, token, user_id: int) -> Optional[UserModel]: """ Deletes a user from the database """ # TODO: Clear from cache (or wait for expiration of the key) headers = self.create_default_header(token) url = self.url_for(f"/user/{user_id}") result = self.requests.delete(url, headers=headers) if result.status_code == 404: raise DoesNotExist(f"User with user id {user_id} not found.") if result.status_code != 200: raise ServerError(f"Wrong status. Expected 200. Got {result.status_code}") return UserModel.parse_obj(result.json())
def get_by_login(self, token: str, login: str) -> UserModel: """ Get a single user by his login, if existent. :Route: ``/user/bylogin/{login}`` :param str token: The authentification token :param str login: The login of the user to be looked up. :return: The found user :rtype: UserModel :raises InsufficientRights: If the requesting user has not the permission. :raises DoesNotExist: if no user exists with the provided login. :raises TokenExpired: is the token has expired. :raises ServerError: if an unpredicted exception occurred. """ headers = self.create_default_header(token) url = self.url_for(f"/user/bylogin/{login}") response = self.requests.get(url, headers=headers) self.check_response_status(response, expected_status=200) return UserModel.parse_obj(response.json())
def rfc_user_set_active_state(data: DataType) -> RfcResponse: user_id = data.get("user_id", None) mode = data.get("mode", "toggle") user = server.user.get(server.token, user_id, fields=["is_active"]) new_state = user.is_active if mode == "toggle": new_state = not new_state elif mode == "on": new_state = True elif mode == "off": new_state = False else: raise ValueError("Unknown mode") if new_state != user.is_active: server.user.update(server.token, UserModel(id=user_id, is_active=new_state)) return RfcResponse(data={"user_id": user_id, "state": new_state})
def me(self, token, fields: XFieldList = None) -> Optional[UserModel]: """ Get a single user """ headers = self.create_default_header(token) if fields is not None: headers[self.X_FILTER_FIELDS] = ",".join(fields) url = self.url_for("/me/") result = self.requests.get(url, headers=headers) if result.status_code == 401: raise TokenExpired("Could not read user details. Token expired.") if result.status_code == 404: return None if result.status_code == 200: return UserModel.parse_obj(result.json()) return None
def verify_user(self, token: str): """ Verifies the user, that is connected to this token. If the token is valid and nor expired, the user, that belongs to this token, will be verified. :Route: /verify/user/{token} :Method: PUT :param str token: The verification token returned by ``get_verification_token`` :return: The verified user. :rtype: :class:`UserModel` :raises InsufficientRights: If the requesting user has not the permission. :raises DoesNotExist: if the user connected to the token does not exist. :raises TokenExpired: is the token has expired. :raises ServerError: if an unpredicted exception occurred. """ url = self.url_for(f"/verify/user/{token}") response = self.requests.put(url) data = response.json() return UserModel.parse_obj(data["user"]), data["token"]
def register(): """ Register a new user. """ # You cannot register, if you are already logged in if account_manager.authenticated: return account_manager.successful_logged_in() form = RegisterForm() if form.validate_on_submit(): try: new_user = UserModel.parse_obj(form.data) new_user.is_active = True new_user.id = None # Just du be shure, we don't have an id in the form accidently # and do an update instead of an creation new_user.is_verified = account_manager.auto_verify # Create a new user in behalf of root result = account_manager.user.register(new_user) new_user, btd = result current_user.set_data(btd) # Also setting the password in behalf of root account_manager.user.set_password(current_user.token, new_user.id, form.password.data) # If the user has been auto verified, we can directly proceed to the login page. # Otherwise we have to show an information to check his email inbox # TODO: Pay respect to both situations. account_manager.logout() return redirect(url_for("account.index")) except DigiCubeError as e: logger.exception("Could not create new account.", exc_info=e) abort(500) return render_template("account/register.jinja", form=form)
def rfc_user_set_verified_state(data: DataType) -> RfcResponse: user_id = data.get("user_id", None) assert user_id is not None, "No user id provided" mode = data.get("mode", "toggle") user = server.user.get(server.token, user_id, fields=["is_verified"]) new_state = user.is_verified if mode == "toggle": new_state = not new_state elif mode == "on": new_state = True elif mode == "off": new_state = False else: raise ValueError("Unknown mode") if new_state != user.is_verified: u = UserModel(id=user_id, is_verified=new_state) u = server.user.update(server.token, u) return RfcResponse(data={"user_id": user_id, "state": new_state})
def get_user_rights(self, user_id: int) -> Optional[List[str]]: raw_data = self.redis.get(f"USER:{user_id}:RIGHTS") return None if raw_data is None else UserModel.parse_obj(raw_data)
def remove_user_role(user_id: int, role_id: int): server.user.remove_role(server.token, UserModel(id=user_id), RoleModel(id=role_id, name="")) return redirect(url_for("user.update", user_id=user_id))
def set_user(self, user: UserModel): key = f"USER:{user.id}" self.redis.set(key, user.json(), ex=self.max_age)