async def on_get(self, req: Request, resp: Response, *, role_id: int, right_id: int): """ Returns a rignt that is associated with a given role. :param int role_id: The id of the role that has to be assiociated with the right. :param int right_id: The id of the right """ try: role = await Role.get(id=role_id).prefetch_related("rights") right = _find_right(role, right_id) if right is not None: # filter_fields = self.get_filter_fields(req) RightModel.from_orm(right).send_json(resp) return resp.status_code = 404 resp.text = f"No role with id '{role_id}' found for right '{right.name} [{right.id}]'." except DoesNotExist: resp.status_code = 404 resp.text = f"No right with id '{right_id}' found." except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))
async def on_get(self, req: Request, resp: Response, *, right_id: int, role_id: int): """ Returns a role that is associated with a given right. :param int right_id: The id of the right :param int role_id: The id of the role that has to be assiociated with the right. """ try: # Prefetching roles for the right specified by its ID. # Requesting only role fields specified by the filter # criterias from ther request header or all, if no # filter was specified. # TODO: Maybe reverse the query, as we are looking for a specific # role. So start with 'await Role.get(...)'. Tis iliminates the need # for an extra search operation (aka find_role) right = await Right.get(id=right_id).prefetch_related( Prefetch("roles", queryset=self.only(req, Role.filter(id=role_id))) ) role = find_role(right, role_id) if role is not None: RoleModel.from_orm(role).send_json(resp) return resp.status_code = 404 resp.text = f"No role with id '{role_id}' found for right '{right.name} [{right.id}]'." except DoesNotExist: resp.status_code = 404 resp.text = f"No right with id '{right_id}' found." except Exception as error: # pylint: disable=broad-except error_response(resp, 500, error)
async def on_post(self, req: Request, resp: Response, *, course_id: int): """ Create a new unit as part of an course """ try: logger.debug("Creating new unit for course %d", course_id) # First check, if this is a valid course which exists course: models.Course = await models.Course.get_or_none( id=course_id) # If not, send a 404 response if course is None: logger.error("Course not found. Unit cannot be created.") resp.status_code = 404 resp.text = f"Course with id {course_id} not found." else: # Read the unit definition from the body. data = await req.media() logger.debug("Provided data %s", data) unit_name = data.get("name", None) if not unit_name: # No unit name? It is mandatory. resp.status_code = 400 resp.text = "No (or empty) unit name provided. Field is mandatory." return # Now see, if this course already has a unit with this name, # as the name has to be unique within the scope of the # course. test_unit: models.Unit = await models.Unit.get_or_none( course=course, name=unit_name) if test_unit is not None: resp.status_code = 409 resp.text = ( f"Course {course.name} [{course.id}] already " f"has a unit with the name {unit_name}. Must be unique." ) return logger.debug("Creating new unit") unit_model = await UnitModel.orm_create_from_obj( course_id=course_id, data=data) unit_model.send_json(resp, status_code=201) except IntegrityError: logger.exception("Could not create unit") resp.status_code = 409 # Conflict resp.text = (f"Course {course.name} [{course.id}] already has a" f"unit with the name {unit_name}. Must be unique.") except Exception as error: # pylint: disable=W0703 logger.exception( "Could not create school, based on data %s", data, exc_info=error, ) error_response(resp, 500, str(error))
async def on_post(self, req: Request, resp: Response): # pylint: disable=C0111 try: data = await req.media() login = data["login"] password = data["password"] logger.debug("User %s tries to login with password: %s", login, password) try: user = await User.get_or_none(login=login, is_verified=True, is_active=True) if user is None: logger.debug( "No user with login found %s. Or not verified or not active", login, ) resp.status_code = 401 resp.text = f"User with login {login} not found or wrong password." return except Exception as error: logger.exception("Could not retrieve user object.") raise DoesNotExist(f"Could not get user {login}") from error # user = await User.get(login=login) logger.debug("Got user. Checking password") if not user.verify_password(password): logger.debug("Wrong password") raise BadPassword() # Remember the date, when the user logged in last user.last_login_at = datetime.utcnow() await user.save() # Create the authentication token. data = create_bearer_token(user.id, req.state.api.secret_key) data.send_json(resp) except BadPassword: logger.debug("Wrong password") resp.status_code = 401 resp.text = f"User with login {login} provided wrong password." except DoesNotExist: logger.debug("No user found") resp.status_code = 401 resp.text = f"User with login {login} not found or wrong password." except KeyError: resp.status_code = 400 resp.text = "Bad formatted body content. Check the documentation" except Exception as error: # pylint: disable=broad-except logger.error("Unexpected error %s", error) resp.status_code = 500 logger.exception("Unexpected error") resp.text = str(error)
async def get_role_by_name(req: Request, resp: Response, *, data): # pylint: disable=unused-variable if req.method == "get": role = await models.Role.get_or_none(name=data) if role is None: resp.status_code = 404 resp.text = f"Role with name {data} not found." else: RoleModel.from_orm(role).send_json(resp) else: resp.status_code = 405 resp.text = "Method not allowed"
async def get_school_by_name(req: Request, resp: Response, *, school_name): # pylint: disable=unused-variable if req.method == "get": school = await models.School.get_or_none(name=school_name) if school is None: resp.status_code = 404 resp.text = f"School with name {school_name} not found." else: SchoolModel.from_orm(school).send_json(resp) else: resp.status_code = 405 resp.text = "Method not allowed"
async def get_user_by_login(req: Request, resp: Response, *, data): # pylint: disable=unused-variable if req.method == "get": user = await UserModel.get(login=data) # user = await models.User.get_or_none(login=data) if user is None: resp.status_code = 404 resp.text = f"User with login {data} not found." else: user.send_json(resp) else: resp.status_code = 405 resp.text = "Method not allowed"
async def on_get(req: Request, resp: Response, *, school_id): try: school = await School.get(id=school_id).prefetch_related('teacher') UserModel.list_model([ UserModel.from_orm(user) for user in school.teacher ]).send_json(resp) except DoesNotExist: resp.status_code = 404 resp.text = f"No school with id {school_id} found." except Exception: # pylint: disable=bare-except resp.status_code = 500 resp.text = f"Could not request teachers for school with id {school_id}" logger.exception("Unable to perform filter")
async def on_delete(self, req: Request, resp: Response, *, school_id: int): """ Delete a school specified by its id. If the school does not exisi, a 404 status code is send back. :param int school_id: The id of the school """ try: school: models.School = await models.School.get_or_none( id=school_id) if school is None: resp.status_code = 404 resp.text = f"School with id {school_id} does not exist." else: await school.delete() # filter_fields = self.get_filter_fields(req) SchoolModel.from_orm(school).send_json(resp) except DoesNotExist: error_response(resp, 404, f"School with id {school_id} does not exist.") except Exception as error: # pylint: disable=W0703 logger.exception("Could not delete school with id %d", school_id) error_response(resp, 500, str(error))
async def on_put(self, req: Request, resp: Response, *, school_id: int) -> None: """ Updates the school """ data = await req.media() # That's not the most elegant version. The two # attributes are write protected, so I pop # the two values from the data dict (if present). data.pop("created_at", None) data.pop("modified_at", None) if not isinstance(data, dict): resp.status_code = 400 # Bad_Request resp.text = "Bad formatted body content" return try: school: models.School = await models.School.get(id=school_id) school.update_from_dict(data) school.modified_at = datetime.utcnow() await school.save() # filter_fields = self.get_filter_fields(req) SchoolModel.from_orm(school).send_json(resp) except DoesNotExist: error_response(resp, 404, f"No school with id {school_id} found.") except Exception as error: # pylint: disable=W0703 logger.exception("Could not update school") error_response(resp, 500, str(error))
async def get_school_teacher(req: Request, resp: Response, *, school_id): if req.method == "get": school = await models.School.get_or_none(id=school_id ).prefetch_related("teacher") if school is None: resp.status_code = 404 resp.text = f"School with id {school_id} not found." else: UserModel.list_model([ UserModel.from_orm(teacher) for teacher in school.teacher ]).send_json(resp) else: resp.status_code = 405 resp.headers["Allow"] = "GET" resp.text = ""
async def on_put(self, req: Request, resp: Response, *, school_id: int, user_id: int): school = await models.School.get_or_none(id=school_id) if school is None: resp.status_code = 404 resp.text = "No school found" return user = await models.User.get_or_none(id=user_id, roles__name="teacher") if user is None: resp.status_code = 404 resp.text = "No user found. Maybe id was wrong or the account is not a teacher." return await school.teacher.add(user) resp.status_code = 200
async def on_get(self, req: Request, resp: Response, user_id: int, space: str) -> None: """ Get a user :param int user_id: The id of the user. """ space_relation = { "student": "student_schools", "headmaster": "principal_schools", "teacher": "teacher_schools", } try: user = None relation = space_relation.get(space, None) if relation is None: resp.status_code = 404 resp.text = "unknown relation type" else: user = await models.User.get_or_none( id=user_id).prefetch_related(relation) SchoolModel.list_model([ SchoolModel.from_orm(school) for school in getattr(user, relation, []) ]).send_json(resp) except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))
async def on_post(self, req: Request, resp: Response, *, right_id: int): """ 405 Method not allowed """ resp.text = "" resp.status_code = 405 resp.headers["Allow"] = self.ALLOWED_METHODS
async def on_delete(self, req: Request, resp: Response, *, school_id: int, user_id: int): school = await models.School.get_or_none(id=school_id) if school is None: resp.status_code = 404 resp.text = "No school found" return user = await models.User.get_or_none(id=user_id) if user is None: resp.status_code = 404 resp.text = "No user found." return await school.teacher.remove(user) resp.status_code = 200
def method_not_allowed(self, resp: Response) -> None: """ Generalized 'method-not-allowed' response. """ resp.text = "" resp.status_code = 405 resp.headers["Allow"] = self.ALLOWED_METHODS
async def on_put(self, req: Request, resp: Response, *, right_id: int, role_id: int): """ Adds another role to this right. Sets the response status code to :code:`200` if the role was added to the right successfully. If :code:`right_id` refers to no existing right, a status code of :code:`404` will be send back. If the specified role already is associated to th right, a status code of ``304 - Not Modified`` is send back. This doesn't fully conform to the http standard, as is does not need any header fields an is not sending back any header fields. But it says clearly what heppend. Because the role is already associated to this right, the right hasn't been modified. :param int right_id: The database id of the right :param int role_id: The database id of the role """ try: right = await Right.get(id=right_id).prefetch_related("roles") if find_role(right, role_id) is None: role = await Role.get(id=role_id) await right.roles.add(role) resp.status_code = 200 # Role added. Great. else: resp.status_code = 304 # Role already related. Not modified except DoesNotExist as error: resp.status_code = 404 resp.text = str(error) except Exception as error: # pylint: disable=broad-except error_response(resp, 500, error)
async def on_post(self, req: Request, resp: Response, *, course_id: int) -> None: """ 405 Method not allowed """ try: resp.status_code = 405 resp.headers["Allow"] = "GET, PUT, DELETE" resp.text = "" except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))
async def on_put(self, req: Request, resp: Response, *, user_id: int): """ 405 Method not allowed """ try: resp.status_code = 405 resp.text = "" resp.headers["Allow"] = self.ALLOWED_METHODS except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))
async def on_get(self, req: Request, resp: Response) -> None: what = req.params.get("w", None) if what == "home_routes": routes = {} for role in await Role.all(): routes[role.name] = role.home_route resp.media = {"home_routes": routes} else: resp.status_code = 404 # File not found resp.text = f"I do not understand {what}"
async def on_get(self, req: Request, resp: Response, *, unit_id: int): """ Get an unit identified by its ID """ logger.debug("Requesting unit with id %d", unit_id) # First check, if this is a valid course which exists db_unit: models.Unit = await models.Unit.get_or_none(id=unit_id) # If not, send a 404 response if db_unit is None: logger.error("UNit not found.") resp.status_code = 404 resp.text = f"Unit with id {unit_id} not found." else: UnitModel.from_orm(db_unit).send_json(resp)
async def on_put(self, req: Request, resp: Response, *, course_id: int) -> None: """ Updates the course. The current course, specified by the ``course_id`` is updated the the json data of the body. The fields id, created_at, modified_at are ignored, as they can not be updated. """ data = await req.media() # That's not the most elegant version. The two # attributes are write protected, so I pop # the two values from the data dict (if present). data.pop("created_at", None) data.pop("modified_at", None) # We also pop the id of the provided json data # as we want to make shure, that the id of the # url is used. data.pop("id", None) if not isinstance(data, dict): resp.status_code = 400 # Bad_Request resp.text = "Bad formatted body content" return try: course: models.Course = await models.Course.get(id=course_id) course.modified_at = datetime.utcnow() course.update(data) course.id = int(course_id) logger.debug(data) await course.save() CourseModel.from_orm(course).send_json(resp) except DoesNotExist: error_response(resp, 404, f"No course with id {course_id} found.") except Exception as error: # pylint: disable=W0703 logger.exception("Could not update course.") error_response(resp, 500, str(error))
async def on_get(self, req: Request, resp: Response, *, course_id: int): """ Returns all units for this course """ try: # First check, if the course exists course = await models.Course.get_or_none(id=course_id) if course is None: resp.status_code = 404 resp.text = f"Course with id {course_id} not found." return units = await models.Unit.filter(course=course ).order_by("position") # filter_fields = self.get_filter_fields(req) UnitModel.list_model([UnitModel.from_orm(unit) for unit in units]).send_json(resp) except Exception as error: # pylint: disable=W0703 logger.exception("Cannot get units for course %d", course_id) error_response(resp, 500, str(error))
async def on_put(self, req: Request, resp: Response, *, unit_id: int): """ Update an unit identified by its ID """ db_unit: models.Unit = await models.Unit.get_or_none(id=unit_id) if db_unit is None: resp.status_code = 404 resp.text = f"Unit with id {unit_id} does not exist." else: data = await req.media() # That's not the most elegant version. The two # attributes are write protected, so I pop # the two values from the data dict (if present). data.pop("created_at", None) data.pop("modified_at", None) db_unit.update(data) db_unit.modified_at = datetime.utcnow() await db_unit.save() UnitModel.from_orm(db_unit).send_json(resp)
async def on_delete(self, req: Request, resp: Response, *, unit_id: int): """ Delete an unit identified by its ID """ try: db_unit: models.Unit = await models.Unit.get_or_none(id=unit_id) if db_unit is None: resp.status_code = 404 resp.text = f"Unit with id {unit_id} does not exist." else: await db_unit.delete() # filter_fields = self.get_filter_fields(req) UnitModel.from_orm(db_unit).send_json(resp) except DoesNotExist: error_response(resp, 404, f"Unit with id {unit_id} does not exist.") except Exception as error: # pylint: disable=W0703 logger.exception("Could not delete unit with id %d", unit_id) error_response(resp, 500, str(error))
async def on_put(self, req: Request, resp: Response, *, role_id: int, right_id: int): """ Adds a right to this role. Sets the response status code to :code:`200` if the right was added to the role successfully. If :code:`role_id` refers to no existing role, a status code of :code:`404` will be send back. If the specified right already is associated to th role, a status code of ``304 - Not Modified`` is send back. This doesn't fully conform to the http standard, as is does not need any header fields an is not sending back any header fields. But it says clearly what happend. Because the right is already associated to this role, the role hasn't been modified. :param int right_id: The database id of the right :param int role_id: The database id of the role """ try: role = await Role.get(id=role_id).prefetch_related("rights") right = _find_right(role, right_id) if right is None: await role.right.add(right) resp.status_code = 200 else: resp.status_code = 304 except DoesNotExist as error: resp.status_code = 404 resp.text = str(error) except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))
async def on_put(self, req: Request, resp: Response, *, role_id: int) -> None: """ Updates the role """ data = await req.media() if not isinstance(data, dict): resp.status_code = 400 # Bad_Request resp.text = "Bad formatted body content" return try: role = await models.Role.get(id=role_id) role.update(data) await role.save() # filter_fields = self.get_filter_fields(req) RoleModel.from_orm(role).send_json(resp) resp.status_code = 200 except DoesNotExist: error_response(resp, 404, f"No role with id {role_id} found.") except Exception as error: # pylint: disable=W0703 error_response(resp, 500, str(error))