Source code for modules.posts

from bson import ObjectId
from modules.database import DB as db
from modules.utils.generals import creation_date
from modules.users import User_lite
from typing import Any, Dict, List, Set, Optional

[docs] class Comment: """Initialize a comment.""" def __init__(self, data: Optional[Dict[str, Any]] = None) -> None: """ Initialize a Comment. Args: data (Optional[Dict[str, Any]], optional): The comment data. Defaults to None. - _id (ObjectId, optional): The comment ID, if isn't given create a new ID. - content (str): The comment text, the content. - rating (float): Comment rating. - creator (User_lite): Comment creator. - createdAt (str, optional): Creation date, if isn't given create a new one. Raises: ValueError: If the data types don't match. """ try: self.valid: bool = True #if not data or any(field is None for field in [data.get("content"), data.get("creator"), data.get("rating")]): if not data: self.valid = False else: self.ID: ObjectId = ObjectId(data.get("_id", ObjectId())) self.content: str = str(data["content"]) self.rating: float = float(data["rating"]) self.creator: User_lite = User_lite(data["creator"]) self.createdAt: str = str(data.get("createdAt", creation_date())) except Exception as e: raise ValueError(f"Error initializing the comment: {e}") def __bool__(self) -> bool: """ The validity of the comment. Returns: bool: True if is valid, else False. """ return self.valid
[docs] def json(self) -> Dict[str, Any]: """ Parse the comment to JSON format. Returns: Dict[str, Any]: Comment data in JSON. """ try: if not self: raise ValueError(f"Error parsing the comment: No data was provided.") return { "_id": self.ID, "content": self.content, "rating": self.rating, "creator": self.creator.json(), "createdAt": self.createdAt } except Exception as e: raise ValueError(f"Error parsing the comment: {e}")
[docs] def filter(self, request_user: User_lite = User_lite()) -> Dict[str, Any]: """ Filter a comment with this params: - Changes "_id" for "ID". - Only returns the creator username. - If the request user is the creator, returns "editable" as True, else False. Args: request_user (User_lite, optional): The user that fetch the comment. Defaults to User_lite(). Raises: RuntimeError: Error filtering the comment. Returns: Dict[str, Any]: The comment filtered. """ try: returned_comment: Dict[str, Any] = self.json() returned_comment["ID"] = str(returned_comment.pop("_id")) returned_comment["creator"] = self.creator.username returned_comment["editable"] = True if request_user == self.creator else False return returned_comment except Exception as e: raise RuntimeError(f"Error filtering the comment: {e}")
[docs] class Post: """Initialize a post.""" def __init__(self, data: Optional[Dict[str, Any]] = None) -> None: """ Initialize a post. Args: data (Optional[Dict[str, Any]], optional): The post data. Defaults to None. - _id (ObjectId, optional): The post ID, if isn't given create a new ID. - name (str): Post's name. - location (str): Post's location. - review (str): Post's review. - rating (float): Post's rating. - imageUrl (str): Post's image url. - creator (User_lite): Post's creator. - comments (List[Dict[str, Any]], optional): The post's comments or [] if isn't given. - createdAt (str, optional): Creation date, if isn't given create a new one. Raises: ValueError: If the data types don't match. """ try: self.valid: bool = True #if not data or any(field is None for field in [data.get("name"), data.get("location"), data.get("review"), data.get("rating"), data.get("imageUrl"), data.get("creator")]): if not data: self.valid = False else: self.ID: ObjectId = ObjectId(data.get("_id", ObjectId())) self.name: str = str(data["name"]) self.location: str = str(data["location"]) self.review: str = str(data["review"]) self.rating: float = float(data["rating"]) self.imageUrl: str = str(data["imageUrl"]) self.creator: User_lite = User_lite(data["creator"]) self.comments: List[Dict[str, Any]] = data.get("comments", []) self.createdAt: str = str(data.get("createdAt", creation_date())) except Exception as e: raise ValueError(f"Error initializing the post. {e}") def __bool__(self) -> bool: """ The validity of the post. Returns: bool: True if is valid, else False. """ return self.valid
[docs] def json(self) -> Dict[str, Any]: """ Parse the post to JSON format. Returns: Dict[str, Any]: Post data in JSON. """ try: if not self: raise ValueError(f"Error parsing the post: No data was provided.") return { "_id": self.ID, "name": self.name, "location": self.location, "review": self.review, "rating": self.rating, "imageUrl": self.imageUrl, "creator": self.creator.json(), "comments": self.comments, "createdAt": self.createdAt } except Exception as e: raise ValueError(f"Error parsing the Post: {e}")
[docs] def filter(self, request_user: User_lite = User_lite()) -> Dict[str, Any]: """ Filter a post with this params: - Changes "_id" for "ID". - Only returns the creator username. - If the request user is the creator, returns "editable" as True, else False. - Filter every comment in the comments. Args: request_user (User_lite, optional): The user that fetch the post. Defaults to User_lite(). Raises: RuntimeError: Error filtering the post. Returns: Dict[str, Any]: The post filtered. """ try: returned_post: Dict[str, Any] = self.json() returned_post["ID"] = str(returned_post.pop("_id")) returned_post["creator"] = self.creator.username returned_post["editable"] = request_user == self.creator returned_post["comments"] = [Comment(comment).filter(request_user) for comment in returned_post["comments"]] return returned_post except Exception as e: raise RuntimeError(f"Error filtering the post: {e}")
[docs] def edit(self, new_info: Dict[str, Any] = {}) -> Dict[str, Any]: """ Edit a post, only in the valid fields: "name", "location", "review", "rating", "imageUrl". Args: new_info (Dict[str, Any], optional): New post's data. Defaults to {}. Raises: RuntimeError: Error editting the post. Returns: Dict[str, Any]: The edited post. """ if not self or not new_info: return {} edited_fields: Dict[str, Any] = {} try: valid_fields: Set[str] = {"name", "location", "review", "rating", "imageUrl"} for key, value in new_info.items(): if key in valid_fields and getattr(self, key, None) != value: setattr(self, key, value) edited_fields[key] = value return edited_fields except Exception as e: raise RuntimeError(f"Error editting the post: {e}")
[docs] def lite(self) -> Dict[str, Any]: """ Make a lite post version, only returns: - ID. - Name. - Location. - Rating. - ImageUrl. Returns: Dict[str, Any]: The lite post. """ if not self: raise ValueError(f"Error liting the post: No data was provided.") try: return { "ID": str(self.ID), "name": self.name, "location": self.location, "rating": self.rating, "imageUrl": self.imageUrl } except Exception as e: raise RuntimeError(f"Error liting the post: {e}") from e
[docs] class Posts: """It manages the posts an comments."""
[docs] @classmethod def get_posts(cls) -> List[Dict[str, Any]]: """ Fetch all the posts in the database. Raises: RuntimeError: Error fetching the posts. Returns: List[Dict[str, Any]]: All posts. """ try: posts: List[Dict[str, Any]] = db.get_posts() return posts except Exception as e: raise RuntimeError(f"Error fetching the posts: {e}") from e
[docs] @classmethod def get_user_posts(cls, user_posts: list = []) -> List[Dict[str, Any]]: """ Fetch all the posts for one user. Args: user_posts (list, optional): The ID of every post to fetch. Defaults to []. Raises: RuntimeError: Error fetching the user posts. Returns: List[Dict[str, Any]]: All user's post or [] if is empty. """ try: posts: List[Dict[str, Any]] = [] for post_id in user_posts: lite: Dict[str, Any] = cls.get_post(post_id).lite() posts.append(lite) return posts except Exception as e: raise RuntimeError(f"Error fetching the user's posts: {e}") from e
[docs] @classmethod def get_post(cls, value: Any, field: str = "_id") -> Post: """ Fetch an specific post. Args: value (Any): Fetch an specific post. field (str, optional): Field to search. Defaults to "_id". Raises: RuntimeError: Error fetching the post. Returns: Post: The post founded. """ try: post: Dict[str, Any] = db.get_post(value, field) return Post(post) except Exception as e: raise RuntimeError(f"Error fetching the post: {e}") from e
[docs] @classmethod def create_post(cls, name: str, location: str, review: str, rating: float, imageUrl: str, creator: User_lite) -> Post: """ Create a new post. Args: name (str): Post's name. location (str): Post's location. review (str): Post's review. rating (float): Post's rating. imageUrl (str): Post's image url. creator (User_lite): Post's creator. Raises: RuntimeError: Error creating the post. Returns: Post: New post data if was created. """ try: new_post: Post = Post({ "name": name, "location": location, "review": review, "rating": rating, "imageUrl": imageUrl, "creator": creator.json() }) return new_post if db.add_post(new_post.json(), creator.ID) else Post() except Exception as e: raise RuntimeError(f"Error creating the post: {e}") from e
[docs] @classmethod def edit_post(cls, post: Post, new_data: Dict[str, Any] = {}) -> Post: """ Edit a post. Args: post (Post): The post to edit. new_data (Dict[str, Any], optional): New data. Defaults to {}. Raises: RuntimeError: Error editing the post. Returns: Post: Edited post if was edited. """ try: edited: Dict[str, Any] = post.edit(new_data) if edited: return post if db.edit_post(post.ID, edited) else Post() return Post() except Exception as e: raise RuntimeError(f"Error editing the post: {e}") from e
[docs] @classmethod def delete_post(cls, post: Post) -> Post: """ Delete a post Args: post (Post): The post to delete. Raises: RuntimeError: Error deleting the post. Returns: Post: Deleted post data. """ try: return post if db.delete_post(post.ID, post.creator.ID) else Post() except Exception as e: raise RuntimeError(f"Error deleting the post: {e}") from e
#Comments @classmethod def __get_comments(cls, post: Post, request_user: User_lite = User_lite()) -> List[Dict[str, Any]]: """ Fetch all the comments in a post. Args: post (Post): The post to fetch comments. request_user (User_lite, optional): The user that makes the request. Defaults to User_lite(). Raises: RuntimeError: Error fetching the comments. Returns: List[Dict[str, Any]]: All the comments or [] if it don't have comments. """ try: db_comments: List[Dict[str, Any]] = db._get_comments(post.ID) comments: List[Dict[str, Any]] = [] for comment in db_comments: comments.append(Comment(comment).filter(request_user)) return comments except Exception as e: raise RuntimeError(f"Error fetching the comments: {e}") from e
[docs] @classmethod def get_comment(cls, post_id: ObjectId, comment_id: ObjectId) -> Comment: """ Fetch one comment in the post. Args: post_id (ObjectId): Post'ID where is the comment. comment_id (ObjectId): Comment's ID to fetch. Raises: RuntimeError: Error fetching a comment. Returns: Comment: The comment fetched if it exist. """ try: comment: Dict[str, Any] = db.get_comment(post_id, comment_id) return Comment(comment) except Exception as e: raise RuntimeError(f"Error fetching the comment. {e}") from e
[docs] @classmethod def new_comment(cls, post: Post, content: str, rating: float, creator: User_lite) -> Comment: """ Create a new comment. Args: post (Post): Post where will be the comment. content (str): Comment's content. rating (float): Comment's rating. creator (User_lite): Comment's creator. Raises: RuntimeError: Error creating the comment Returns: Comment: New comment data if was added. """ try: new_comment: Comment = Comment({ "content": content, "rating": rating, "creator": creator.json() }) return new_comment if db.add_comment(post.ID, new_comment.json()) else Comment() except Exception as e: raise RuntimeError(f"Error creating the comment: {e}") from e
[docs] @classmethod def delete_comment(cls, post: Post, comment: Comment) -> Comment: """ Delete a comment. Args: post (Post): Post where is the comment. comment (Comment): Comment to delete. Raises: RuntimeError: Error deleting the comment. Returns: Comment: Deleted comment data. """ try: return comment if db.delete_comment(post.ID, comment.ID) else Comment() except Exception as e: raise RuntimeError(f"Error deleting the comment: {e}") from e