//! # Posts helper //! //! @author Pierre Hubert use crate::constants::database_tables_names::POSTS_TABLE; use crate::data::error::{ExecError, ResultBoxError}; use crate::data::group_member::GroupMembershipLevel; use crate::data::post::{Post, PostAccessLevel, PostFile, PostKind, PostPageKind, PostVisibilityLevel, PostWebLink}; use crate::data::post::PostKind::{POST_KIND_COUNTDOWN, POST_KIND_IMAGE, POST_KIND_MOVIE, POST_KIND_PDF, POST_KIND_SURVEY, POST_KIND_WEBLINK, POST_KIND_YOUTUBE}; use crate::data::user::UserID; use crate::helpers::{database, friends_helper, groups_helper, user_helper}; use crate::utils::date_utils::time; impl PostVisibilityLevel { pub fn to_db(&self) -> u32 { match self { PostVisibilityLevel::VISIBILITY_PUBLIC => 1, PostVisibilityLevel::VISIBILITY_FRIENDS => 2, PostVisibilityLevel::VISIBILITY_USER => 3, PostVisibilityLevel::VISIBILITY_GROUP_MEMBERS => 50, } } pub fn from_db(val: u32) -> PostVisibilityLevel { match val { 1 => PostVisibilityLevel::VISIBILITY_PUBLIC, 2 => PostVisibilityLevel::VISIBILITY_FRIENDS, 3 => PostVisibilityLevel::VISIBILITY_USER, 50 => PostVisibilityLevel::VISIBILITY_GROUP_MEMBERS, _ => PostVisibilityLevel::VISIBILITY_PUBLIC, } } } pub struct PostsQuery { /// The ID of the user making the request user_id: Option, /// Maximum number of posts to get limit: u64, /// Starting post start_from: u64, } impl PostsQuery { /// Construct a new request pub fn new(user_id: Option) -> PostsQuery { PostsQuery { user_id, limit: 10, start_from: 0, } } /// Start starting point pub fn set_start_from(mut self, start_from: u64) -> PostsQuery { self.start_from = start_from; self } /// Set the limit for this query pub fn set_limit(mut self, limit: u64) -> PostsQuery { self.limit = limit; self } /// Get the posts of a user pub fn get_user(self, user_id: &UserID) -> ResultBoxError> { get_user(&self, user_id) } } /// Get the posts of `target_id` fn get_user(query: &PostsQuery, target_id: &UserID) -> ResultBoxError> { // Max user visibility let mut level = PostVisibilityLevel::VISIBILITY_PUBLIC; if let Some(user_id) = &query.user_id { if user_id == target_id { level = PostVisibilityLevel::VISIBILITY_USER; } else if friends_helper::are_friend(user_id, target_id)? { level = PostVisibilityLevel::VISIBILITY_FRIENDS; } } // Start request let mut db_query = database::QueryInfo::new(POSTS_TABLE); let mut custom_where = String::new(); // Preprocess conditions // ============= PERMISSION CONDITIONS ================= custom_where.push_str("((niveau_visibilite <= ?) "); db_query = db_query.add_custom_where_argument_u32(level.to_db()); // Add user posts (if signed in) if let Some(user_id) = &query.user_id { custom_where.push_str(" OR (ID_amis = ?) "); db_query = db_query.add_custom_where_argument_user_id(user_id); } custom_where.push_str(")"); // ============= /PERMISSION CONDITIONS ================= // ============== START POINT CONDITION ================= if query.start_from != 0 { custom_where.push_str(" AND ID <= ?"); db_query = db_query.add_custom_where_argument_u64(query.start_from); } // ============== /START POINT CONDITION ================ // Perform the request db_query .cond_user_id("ID_personne", target_id) .cond_u64("group_id", 0) .set_custom_where(&custom_where) .set_order("ID DESC") .set_limit(query.limit) .exec(db_to_post) } /// Get the access level of a user over a post pub fn get_access_level(p: &Post, user_id: &Option) -> ResultBoxError { if user_id == &p.user_id.as_option() { return Ok(PostAccessLevel::FULL_ACCESS); } match &p.target_page { // User page PostPageKind::PAGE_KIND_USER(user_page_id) => { if &user_page_id.as_option() == user_id { return Ok(PostAccessLevel::INTERMEDIATE_ACCESS); } return match p.visibility { PostVisibilityLevel::VISIBILITY_PUBLIC => { if user_helper::can_see_user_page(user_id.as_ref().unwrap_or(&UserID::invalid()), user_page_id)? { Ok(PostAccessLevel::BASIC_ACCESS) } else { Ok(PostAccessLevel::NO_ACCESS) } } PostVisibilityLevel::VISIBILITY_FRIENDS => { if user_id.is_some() && friends_helper::are_friend(user_id.as_ref().unwrap_or(&UserID::invalid()), user_page_id)? { Ok(PostAccessLevel::BASIC_ACCESS) } else { Ok(PostAccessLevel::NO_ACCESS) } } // No access to posts with restricted visibility PostVisibilityLevel::VISIBILITY_USER => Ok(PostAccessLevel::NO_ACCESS), _ => Ok(PostAccessLevel::NO_ACCESS), }; } // Group page PostPageKind::PAGE_KIND_GROUP(group_id) => { let access_level = groups_helper::get_membership_level(group_id, user_id.clone())?; // Moderators & administrators if access_level < GroupMembershipLevel::MEMBER { Ok(PostAccessLevel::INTERMEDIATE_ACCESS) } else if access_level == GroupMembershipLevel::MEMBER { Ok(PostAccessLevel::BASIC_ACCESS) } else if p.visibility != PostVisibilityLevel::VISIBILITY_PUBLIC || !groups_helper::is_open(group_id)? { Ok(PostAccessLevel::NO_ACCESS) } else { Ok(PostAccessLevel::BASIC_ACCESS) } } } } /// Check out whether it is possible to create comments on a post or not pub fn allow_comments_on_post(p: &Post) -> ResultBoxError { Ok( !p.is_on_user_page() || user_helper::allow_comments(p.user_page_id().unwrap_or(&UserID::invalid()))?) } /// Turn a post into a database entry fn db_to_post(res: &database::RowResult) -> ResultBoxError { let user_id = if res.get_u64("ID_amis")? == 0 { res.get_user_id("ID_personne") } else { res.get_user_id("ID_amis") }?; let target_page = if res.get_u64("group_id")? == 0 { PostPageKind::PAGE_KIND_USER(res.get_user_id("ID_personne")?) } else { PostPageKind::PAGE_KIND_GROUP(res.get_group_id("group_id")?) }; let file = match res.get_optional_str("path")? { None => None, Some(path) => Some(PostFile { path, size: res.get_usize("size").unwrap_or(0), file_type: res.get_optional_str("file_type")?, }), }; let mut post = Post { // General information id: res.get_u64("ID")?, user_id: user_id.clone(), time_create: res.get_u64("time_insert").unwrap_or(time()), target_page, content: res.get_optional_str("texte")?, visibility: PostVisibilityLevel::from_db(res.get_u32("niveau_visibilite")?), kind: PostKind::POST_KIND_TEXT, }; let file = file.ok_or(ExecError::new("A file is required with this post type!")); match res.get_str("type")?.as_str() { "image" => post.kind = POST_KIND_IMAGE(file?), "webpage_link" => post.kind = POST_KIND_WEBLINK(PostWebLink { url: res.get_str("url_page")?, title: res.get_optional_str("titre_page")?, description: res.get_optional_str("description_page")?, image: res.get_optional_str("image_page")?, }), "pdf" => post.kind = POST_KIND_PDF(file?), "video" => post.kind = POST_KIND_MOVIE(res.get_u64("idvideo")?), "count_down" => post.kind = POST_KIND_COUNTDOWN(res.get_u64("time_end").unwrap_or(0)), "sondage" => post.kind = POST_KIND_SURVEY, "youtube" => post.kind = POST_KIND_YOUTUBE(res.get_str("path")?), _ => {} } Ok(post) }