async def create_comment(res: Response, comment: dict) -> Dict[str, Any]:
    """Create new comment\n

    Args:\n
        comment (dict): Comment to create\n

    Returns:\n
        Dict[str, Any]: Comment created\n
    """
    data = {
        "success": True,
        "comment": {},
        "detail": "Comment successfully created",
    }
    comment_owner = API_functools.get_or_default(
        await Person.filter(pk=comment.get("user", 0)), 0, None)

    if comment_owner is None:
        res.status_code = status.HTTP_404_NOT_FOUND
        data["success"] = False
        data["detail"] = "Comment owner doesn't exist"
        return data
    comment["user"] = comment_owner
    data["comment"] = API_functools.tortoise_to_dict(await
                                                     Comment.create(**comment))
    return jsonable_encoder(data)
Exemple #2
0
async def users(
    request: Request,
    res: Response,
    limit: Optional[int] = 20,
    offset: Optional[int] = 0,
    sort: Optional[str] = "id:asc",
) -> Optional[List[Dict[str, Any]]]:
    """Get all users or some of them using 'offset' and 'limit'

    Args:

        limit (int, optional): max number of returned users.
        Defaults to 100.
        offset (int, optional): first user to return (use with limit).
        Defaults to 1.
        sort (str, optional): the order of the result.
        attribute:(asc {ascending} or desc {descending}).
        Defaults to "id:asc".

    Returns:

        Optional[List[Dict[str, Any]]]: list of users found or
        Dict with error
    """
    response = {
        "success": False,
        "users": [],
    }
    order_by = API_functools.valid_order(Person, sort)
    if order_by is None:
        res.status_code = status.HTTP_400_BAD_REQUEST
        return {
            **response,
            "detail":
            "Invalid sort parameters. it must match \
            attribute:order. ex: id:asc or id:desc",
        }

    if offset < 0 or limit < 1:
        res.status_code = status.HTTP_400_BAD_REQUEST
        return {
            **response,
            "detail": "Invalid values: offset(>=0) or limit(>0)",
        }
    nb_users = await Person.all().count()

    users = await Person_Pydantic.from_queryset(
        Person.all().limit(limit).offset(offset).order_by(order_by))

    if len(users) == 0:
        res.status_code = status.HTTP_404_NOT_FOUND
        return {**response, "detail": "Not Found"}

    return API_functools.manage_next_previous_page(request, users, nb_users,
                                                   limit, offset)
 async def test_instance_of(self):
     obj = await Person.create(**INIT_DATA.get("person", [])[0])
     elements = {
         "Hello World": str,
         1: int,
         obj: Person,
         (1, 2, 3, 4): tuple,
     }
     for el, instance in elements.items():
         assert API_functools.instance_of(el, instance) is True
     assert API_functools.instance_of("Hello", int) is False
async def filter_comments(
    req: Request,
    res: Response,
    max_comments: int,
    data: Optional[list[dict]] = None,
    filters: Optional[dict] = None,
    offset: Optional[int] = 20,
    limit: Optional[int] = 0,
    sort: Optional[str] = "id:asc",
):

    response = {
        "success": False,
        "comments": [],
    }
    if data is None:
        order_by = API_functools.valid_order(Comment, sort)
        if order_by is None:
            res.status_code = status.HTTP_400_BAD_REQUEST
            return {
                **response,
                "detail": invalid_sort_detail,
            }

    if offset < 0 or limit < 1:
        res.status_code = status.HTTP_400_BAD_REQUEST
        return {
            **response,
            "detail": "Invalid values: offset(>=0) or limit(>0)",
        }
    if data is None:
        comments = await API_functools.add_owner_fullname(
            jsonable_encoder(await (
                Comment.all() if filters is None else Comment.filter(**filters)
            ).prefetch_related("vote").prefetch_related("children").annotate(
                votes=Count("vote", distinct=True)
            ).annotate(nb_children=Count("children", distinct=True)
                       ).limit(limit).offset(offset).order_by(order_by).values(
                           *API_functools.get_attributes(Comment), "votes",
                           "nb_children")))
    else:
        comments = data

    if len(comments) == 0:
        res.status_code = status.HTTP_404_NOT_FOUND
        return {**response, "detail": "Not Found"}
    return API_functools.manage_next_previous_page(req,
                                                   comments,
                                                   max_comments,
                                                   limit,
                                                   offset,
                                                   data_type="comments")
Exemple #5
0
async def users_by_attribute(res: Response, user_attribute: Any,
                             value: Any) -> List[Dict[str, Any]]:
    """Get user by attribute except

    Args:

        user_attribute (Any): user's attribute
        you can combine two or more attributes with keywords "Or", "And"
        ex: idOremail, genderAndemail

    Returns:
        List[Dict[str, Any]]: List of users found
    """
    response = {"success": False, "users": []}
    lower_user_attribute = user_attribute.lower()
    if ("and" not in lower_user_attribute and "or" not in lower_user_attribute
        ) and not API_functools.is_attribute_of(user_attribute, Person):
        res.status_code = status.HTTP_400_BAD_REQUEST
        return {
            **response,
            "detail":
            f"""
            Invalid attribute filter.
            Try with: {API_functools.get_attributes(Person)}
            """,
        }
    query_builder = Database.query_filter_builder(user_attribute, value)

    persons = await Person_Pydantic.from_queryset(
        Person.filter(*query_builder).order_by("id"))
    if len(persons) == 0:
        res.status_code = status.HTTP_404_NOT_FOUND
        return {**response, "detail": "Not Found"}

    return {"success": True, "users": persons}
async def fix_comment(res: Response, comment_ID: int,
                      comment_data: PartialComment) -> Dict[str, Any]:
    """Fix some comment attributes according to PartialComment class\n

    Args:\n
        comment_ID (int): user ID\n
        comment_data (PartialComment): new data\n

    Returns:\n
        Dict[str, Any]: contains updated Comment data or error\n
    """
    response = {"success": True, "comment": {}}

    comment_found = await Comment.get_or_none(id=comment_ID)
    if comment_found is None:
        res.status_code = status.HTTP_404_NOT_FOUND
        response["success"] = False
        response["detail"] = f"Comment with ID {comment_ID} doesn't exist."
        return response

    comment_updated = comment_found.update_from_dict(comment_data.__dict__)
    await comment_updated.save()
    response["detail"] = "Comment successfully patched"
    response["comment"] = API_functools.tortoise_to_dict(comment_updated)
    return jsonable_encoder(response)
async def update_comment(res: Response, comment_ID: int,
                         comment_data: CommentBaseModel) -> Dict[str, Any]:
    """Update comment attributes according to CommentBaseModel class\n

    Args:\n
        comment_ID (int): comment to update\n
        comment_data (CommentBaseModel): new comment data\n

    Returns:\n
        Dict[str, Any]: contains comment new data or error\n
    """
    response = {"success": True, "comment": {}}

    new_owner = await Person.get_or_none(id=comment_data.user)
    if new_owner is None:
        res.status_code = status.HTTP_404_NOT_FOUND
        response["success"] = False
        response["detail"] = "Comment owner doesn't exist."
        return response

    comment_found = await Comment.get_or_none(id=comment_ID)
    if comment_found is None:
        res.status_code = status.HTTP_404_NOT_FOUND
        response["success"] = False
        response["detail"] = f"Comment with ID {comment_ID} doesn't exist."
        return response

    comment_data.user = new_owner

    comment_updated = comment_found.update_from_dict(comment_data.__dict__)
    await comment_updated.save()
    response["detail"] = "Comment successfully updated"
    response["comment"] = API_functools.tortoise_to_dict(comment_updated)
    return jsonable_encoder(response)
    async def json_children(
        self, fields: list[str] = [], order_by: str = "id", deep: bool = False
    ) -> dict[str, Any]:
        """return all comments child of current comment
        (comments that reply to the current comment)

        Args:

            fields (list[str]): list of fields to return, default []
            order_by (str, optional): ordering return. Defaults to "id".
            deep (bool: optional): get/not also deep children
            (response to child's comment)

        Returns:

            dict[str, Any]: data found
        """
        from app.api.utils import API_functools

        fields = fields if len(fields) > 0 else API_functools.get_attributes(Comment)
        filter_key = {"top_parent_id" if deep else "parent_id": self.id}
        return await API_functools.add_owner_fullname(
            jsonable_encoder(
                await (
                    Comment.filter(**filter_key)
                    .prefetch_related("vote")
                    .annotate(votes=Count("vote", distinct=True))
                    .annotate(nb_children=Count("children", distinct=True))
                    .order_by(order_by)
                    .values(*fields, "votes", "nb_children")
                )
            )
        )
 def test_get_or_default(self):
     list_object = (
         {
             "name": "John Doe"
         },
         {
             "name": "Bob Doe"
         },
         {
             "name": "Alice Doe"
         },
     )
     for index, obj in enumerate(list_object):
         assert API_functools.get_or_default(list_object, index,
                                             None) == obj
     assert API_functools.get_or_default(list_object, len(list_object),
                                         None) is None
 def test_valid_order(self):
     # valid order must consist of an attribute of the Person class
     # and the word "asc" or "desc"
     orders = [
         ("first_name", None),
         ("notattributte:asc", None),
         ("id:notvalidkeyword", None),
         ("first_name:asc", "first_name"),
         ("first_name:desc", "-first_name"),
     ]
     for order in orders:
         assert API_functools.valid_order(Person, order[0]) == order[1]
Exemple #11
0
async def users_by_ID(res: Response, user_ID: int) -> Dict[str, Any]:
    """Get user by ID

    Args:

        user_ID (int): user ID

    Returns:

        Dict[str, Any]: user found or Error
    """
    user = await Person_Pydantic.from_queryset(Person.filter(pk=user_ID))
    data = {
        "success": True,
        "user": API_functools.get_or_default(user, 0, {}),
    }
    if not API_functools.instance_of(data["user"], Person):
        res.status_code = status.HTTP_404_NOT_FOUND
        data["success"] = False
        data["detail"] = "Not Found"
    return data
 def test_comment_attributes(self):
     expected_attrs = (
         "id",
         "added",
         "edited",
         "content",
         "parent_id",
         "user_id",
         "top_parent_id",
     )
     actual_attrs = API_functools.get_attributes(Comment)
     for attr in expected_attrs:
         assert attr in actual_attrs
     assert len(expected_attrs) == len(actual_attrs)
    async def test__insert_default_data(self):
        # Insert a Person
        user_to_create = INIT_DATA.get("person", [])[0]
        user_created = await API_functools._insert_default_data(
            "person", user_to_create)
        assert API_functools.instance_of(user_created, Person) is True

        # Insert a Comment
        comment_to_create = {
            **INIT_DATA.get("comment", [])[0],
            "user": user_created.id,
        }
        comment_created = await API_functools._insert_default_data(
            "comment", comment_to_create)
        assert API_functools.instance_of(comment_created, Comment) is True

        # Insert a Vote
        vote_to_create = {
            "user": user_created.id,
            "comment": comment_created.id,
        }
        vote_created = await API_functools._insert_default_data(
            "vote", vote_to_create)
        assert API_functools.instance_of(vote_created, Vote) is True
 def test_manage_next_previous_page(self):
     scope = {"type": "http", "path": "/", "method": "GET"}
     request = Request(scope)
     scenes = [
         {
             "data": (0, 5, 0),  # nb_total_data, limit, offset
             "expected": {
                 "next": None,
                 "previous": None,
                 "success": False,
                 "users": [],
             },
         },
         {
             "data": (15, 5, 5),
             "expected": {
                 "next": "/?limit=5&offset=10",
                 "previous": "/?limit=5&offset=0",
                 "success": False,
                 "users": [],
             },
         },
         {
             "data": (10, 5, 0),
             "expected": {
                 "next": "/?limit=5&offset=5",
                 "previous": None,
                 "success": False,
                 "users": [],
             },
         },
         {
             "data": (10, 5, 5),
             "expected": {
                 "next": None,
                 "previous": "/?limit=5&offset=0",
                 "success": False,
                 "users": [],
             },
         },
     ]
     for scene in scenes:
         # scene 1 next=None, previous=None
         actual = API_functools.manage_next_previous_page(request, [],
                                                          *scene["data"],
                                                          data_type="users")
         assert actual == scene["expected"]
 async def test_tortoise_to_dict(self):
     actual = API_functools.tortoise_to_dict(
         await Person(**INIT_DATA.get("person", [])[0]))
     actual["date_of_birth"] = jsonable_encoder(actual["date_of_birth"])
     assert actual == {
         "avatar": avatar,
         "company": "Edgetag",
         "country_of_birth": "Egypt",
         "date_of_birth": "1978-04-15",
         "email": "*****@*****.**",
         "first_name": "Shalom",
         "gender": "Male",
         "id": None,
         "is_admin": True,
         "job": "Compensation Analyst",
         "last_name": "Handes",
     }
 def test_user_attributes(self):
     expected_attrs = (
         "id",
         "is_admin",
         "first_name",
         "last_name",
         "email",
         "gender",
         "avatar",
         "job",
         "company",
         "date_of_birth",
         "country_of_birth",
     )
     actual_attrs = API_functools.get_attributes(Person)
     for attr in expected_attrs:
         assert attr in actual_attrs
     assert len(expected_attrs) == len(actual_attrs)
 def test_get_attributes(self):
     # Test get_attribute with kwargs
     user_attributes = (
         "id",
         "is_admin",
         "name",
         "email",
         "gender",
         "avatar",
         "job",
         "company",
         "date_of_birth",
         "country_of_birth",
         "full_name",
     )
     assert (API_functools.get_attributes(
         Person,
         replace={"first_name": "name"},
         add=("full_name", ),
         exclude=("last_name", ),
     ) == user_attributes)
Exemple #18
0
async def delete_comment(res: Response, comment_ID: int) -> Dict[str, Any]:
    """Delete a comment\n

    Args:\n
        comment_ID (int): comment to delete\n

    Returns:\n
        Dict[str, Any]: contains deleted comment data or error\n
    """
    response = {"success": False, "comment": {}}

    comment_found = await Comment.get_or_none(id=comment_ID)
    if comment_found is None:
        res.status_code = status.HTTP_404_NOT_FOUND
        response["detail"] = f"Comment with ID {comment_ID} doesn't exist"
        return response

    await comment_found.delete()

    response["success"] = True
    response["comment"] = API_functools.tortoise_to_dict(comment_found)
    response["detail"] = f"Comment {comment_ID} deleted successfully тнР"
    return jsonable_encoder(response)
 def test_strip_spaces(self):
     s = API_functools.strip_spaces("       Hello         World       ")
     assert s == "Hello World"
Exemple #20
0
async def comments_by_ID(
    req: Request,
    res: Response,
    comment_ID: int,
    children: bool = False,
    limit: Optional[int] = 20,
    offset: Optional[int] = 0,
    sort: Optional[str] = "id:asc",
) -> Dict[str, Any]:
    """Get comment by ID

    Args:

        comment_ID (int): comment ID
        children (bool): get current comment children
        limit (int, optional): max number of returned comments.
            Defaults to 100.
        offset (int, optional): first comment to return (use with limit).
            Defaults to 1.
        sort (str, optional): the order of the result.
            attribute:(asc {ascending} or desc {descending}). Defaults to "id:asc".

    Returns:

        Dict[str, Any]: contains comment found
    """
    key, value = ("comment", {}) if not children else ("comments", [])
    response = {"success": True, key: value, "detail": "Successful operation"}

    if not await Comment.exists(pk=comment_ID):
        res.status_code = status.HTTP_404_NOT_FOUND
        response["success"] = False
        response["detail"] = "Not Found"
        return response

    if children:
        order_by = API_functools.valid_order(Comment, sort)

        if order_by is None:
            res.status_code = status.HTTP_400_BAD_REQUEST
            return {
                **response,
                "success": False,
                "detail": invalid_sort_detail,
            }
        comment = await Comment.filter(pk=comment_ID).first()
        comments = await comment.json_children(order_by=order_by)
        response["comments"] = comments
        return await filter_comments(
            req,
            res,
            len(response["comments"]),
            data=response["comments"],
            offset=offset,
            limit=limit,
            sort=sort,
        )

    else:
        response["comment"] = API_functools.get_or_default(
            await API_functools.add_owner_fullname([
                API_functools.get_or_default(
                    jsonable_encoder(await Comment.filter(
                        pk=comment_ID
                    ).prefetch_related("vote").prefetch_related(
                        "children").annotate(
                            votes=Count("vote", distinct=True)
                        ).annotate(nb_children=Count("children", distinct=True)
                                   ).values(
                                       *API_functools.get_attributes(Comment),
                                       "votes",
                                       "nb_children",
                                   )),
                    index=0,
                    default={},
                )
            ]),
            index=0,
            default={},
        )

    return response
 def test_is_attribute_of(self):
     for attr in API_functools.get_attributes(Person):
         assert API_functools.is_attribute_of(attr, Person) is True
     assert API_functools.is_attribute_of("invalid", Person) is False