Пример #1
0
    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))
Пример #2
0
    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)
Пример #3
0
    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))
Пример #4
0
    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)
Пример #5
0
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"
Пример #6
0
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"
Пример #7
0
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"
Пример #8
0
    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")
Пример #9
0
    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))
Пример #10
0
    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))
Пример #11
0
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 = ""
Пример #12
0
    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
Пример #13
0
    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))
Пример #14
0
 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
Пример #15
0
    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
Пример #16
0
 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
Пример #17
0
    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)
Пример #18
0
    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))
Пример #19
0
    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))
Пример #20
0
    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}"
Пример #21
0
    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)
Пример #22
0
    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))
Пример #23
0
    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))
Пример #24
0
    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)
Пример #25
0
    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))
Пример #26
0
    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))
Пример #27
0
    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))