mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 01:24:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			298 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
//! # Posts controller
 | 
						|
//!
 | 
						|
//! @author Pierre Hubert
 | 
						|
 | 
						|
use crate::api_data::post_api::PostAPI;
 | 
						|
use crate::api_data::posts_targets_api::PostsTargets;
 | 
						|
use crate::api_data::res_create_post::ResCreatePost;
 | 
						|
use crate::constants::{PATH_POST_IMAGES, PATH_POST_PDF};
 | 
						|
use crate::data::base_request_handler::BaseRequestHandler;
 | 
						|
use crate::data::error::{ExecError, ResultBoxError};
 | 
						|
use crate::data::group::GroupAccessLevel;
 | 
						|
use crate::data::http_request_handler::HttpRequestHandler;
 | 
						|
use crate::data::new_survey::NewSurvey;
 | 
						|
use crate::data::notification::NotifEventType;
 | 
						|
use crate::data::post::{
 | 
						|
    Post, PostAccessLevel, PostFile, PostKind, PostPageKind, PostVisibilityLevel, PostWebLink,
 | 
						|
};
 | 
						|
use crate::helpers::{
 | 
						|
    friends_helper, groups_helper, notifications_helper, posts_helper, survey_helper, user_helper,
 | 
						|
};
 | 
						|
use crate::routes::RequestResult;
 | 
						|
use crate::utils::date_utils::time;
 | 
						|
use crate::utils::string_utils::{check_string_before_insert, check_youtube_id};
 | 
						|
use crate::utils::user_data_utils::user_data_path;
 | 
						|
use crate::utils::webpage_utils::get_post_web_link;
 | 
						|
 | 
						|
impl PostFile {
 | 
						|
    /// Initialize a `PostFile` instance based on a file that have just been created
 | 
						|
    pub fn new_from_created_file(path: &str) -> ResultBoxError<PostFile> {
 | 
						|
        let data = std::fs::metadata(user_data_path(path.as_ref()))?;
 | 
						|
        Ok(PostFile {
 | 
						|
            path: path.to_string(),
 | 
						|
            size: data.len() as usize,
 | 
						|
            file_type: mime_guess::from_path(path)
 | 
						|
                .first()
 | 
						|
                .map(|m| format!("{}/{}", m.type_(), m.subtype())),
 | 
						|
        })
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Get the list of posts of a user
 | 
						|
pub async fn get_list_user(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let user_id = r.post_user_id("userID")?;
 | 
						|
    let start_from = r.post_u64_opt("startFrom", 0)?;
 | 
						|
 | 
						|
    if !user_helper::can_see_user_page(r.user_id_ref()?, &user_id)? {
 | 
						|
        r.forbidden("You are not allowed to access this user posts !".to_string())?;
 | 
						|
    }
 | 
						|
 | 
						|
    let posts = posts_helper::PostsQuery::new(r.user_id_opt())
 | 
						|
        .set_start_from(start_from)
 | 
						|
        .get_user(&user_id)?;
 | 
						|
 | 
						|
    r.set_response(PostAPI::for_list(&posts, r.user_id_opt())?)
 | 
						|
}
 | 
						|
 | 
						|
/// Get the list of posts of a group
 | 
						|
pub async fn get_list_group(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::VIEW_ACCESS)?;
 | 
						|
    let start_from = r.post_u64_opt("startFrom", 0)?;
 | 
						|
 | 
						|
    let posts = posts_helper::PostsQuery::new(r.user_id_opt())
 | 
						|
        .set_start_from(start_from)
 | 
						|
        .get_group(&group_id)?;
 | 
						|
 | 
						|
    r.set_response(PostAPI::for_list(&posts, r.user_id_opt())?)
 | 
						|
}
 | 
						|
 | 
						|
/// Get the latest posts of a group
 | 
						|
pub async fn get_latest(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let start_from = r.post_u64_opt("startFrom", 0)?;
 | 
						|
    let include_groups = r.post_bool_opt("include_groups", false);
 | 
						|
 | 
						|
    let posts = posts_helper::PostsQuery::new(r.user_id_opt())
 | 
						|
        .set_start_from(start_from)
 | 
						|
        .get_latest(include_groups)?;
 | 
						|
 | 
						|
    r.set_response(PostAPI::for_list(&posts, r.user_id_opt())?)
 | 
						|
}
 | 
						|
 | 
						|
/// Get information about a single post
 | 
						|
pub async fn get_single(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let post = r.post_post_with_access("postID", PostAccessLevel::BASIC_ACCESS)?;
 | 
						|
 | 
						|
    r.set_response(PostAPI::new(&post, &r.user_id_opt())?)
 | 
						|
}
 | 
						|
 | 
						|
/// Create a new post
 | 
						|
pub async fn create_post(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    // Process page target
 | 
						|
    let target_page = match r.post_string("kind-page")?.as_str() {
 | 
						|
        "user" => {
 | 
						|
            let user_id = r.post_user_id("kind-id")?;
 | 
						|
 | 
						|
            if !user_helper::can_create_posts(r.user_id_ref()?, &user_id)? {
 | 
						|
                r.forbidden("You are not allowed to create posts on this page!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            PostPageKind::PAGE_KIND_USER(user_id)
 | 
						|
        }
 | 
						|
 | 
						|
        "group" => {
 | 
						|
            let group_id =
 | 
						|
                r.post_group_id_with_access("kind-id", GroupAccessLevel::MEMBER_ACCESS)?;
 | 
						|
 | 
						|
            if !groups_helper::can_user_create_posts(&group_id, r.user_id_ref()?)? {
 | 
						|
                r.forbidden("You are not allowed to create posts on this group!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            PostPageKind::PAGE_KIND_GROUP(group_id)
 | 
						|
        }
 | 
						|
 | 
						|
        _ => {
 | 
						|
            r.not_found("Unsupported target page type!".to_string())?;
 | 
						|
            unreachable!();
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // Start to create post
 | 
						|
    let mut post = Post {
 | 
						|
        id: 0,
 | 
						|
        user_id: r.user_id()?,
 | 
						|
        time_create: time(),
 | 
						|
        target_page,
 | 
						|
        content: Some(r.post_string_opt("content", 0, false)?),
 | 
						|
        visibility: PostVisibilityLevel::from_api(&r.post_string("visibility")?),
 | 
						|
        kind: PostKind::POST_KIND_TEXT,
 | 
						|
    };
 | 
						|
 | 
						|
    let mut new_survey = None;
 | 
						|
 | 
						|
    // Handle different post types
 | 
						|
    post.kind = match r.post_string("kind")?.as_str() {
 | 
						|
        // Text posts
 | 
						|
        "text" => {
 | 
						|
            if !check_string_before_insert(post.content.as_ref().unwrap_or(&String::new())) {
 | 
						|
                r.forbidden("Specified post content is invalid!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            PostKind::POST_KIND_TEXT
 | 
						|
        }
 | 
						|
 | 
						|
        // Image post
 | 
						|
        "image" => {
 | 
						|
            if !r.has_file("image") {
 | 
						|
                r.bad_request("An error occured while receiving the image!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            let path = r.save_post_image("image", PATH_POST_IMAGES, 2000, 2000)?;
 | 
						|
 | 
						|
            PostKind::POST_KIND_IMAGE(PostFile::new_from_created_file(&path)?)
 | 
						|
        }
 | 
						|
 | 
						|
        // YouTube posts
 | 
						|
        "youtube" => {
 | 
						|
            let youtube = r.post_string("youtube_id")?;
 | 
						|
 | 
						|
            if !check_youtube_id(&youtube) {
 | 
						|
                r.bad_request("Invalid YouTube ID!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            PostKind::POST_KIND_YOUTUBE(youtube)
 | 
						|
        }
 | 
						|
 | 
						|
        // Weblink posts
 | 
						|
        "weblink" => {
 | 
						|
            let url = r
 | 
						|
                .post_url_opt("url", true)?
 | 
						|
                .ok_or(ExecError::new("Missing url!"))?;
 | 
						|
 | 
						|
            match get_post_web_link(&url) {
 | 
						|
                Ok(info) => PostKind::POST_KIND_WEBLINK(info),
 | 
						|
                Err(e) => {
 | 
						|
                    eprintln!("Error while fetching page metadata: {}", e);
 | 
						|
                    PostKind::POST_KIND_WEBLINK(PostWebLink {
 | 
						|
                        url,
 | 
						|
                        title: None,
 | 
						|
                        description: None,
 | 
						|
                        image: None,
 | 
						|
                    })
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        "pdf" => {
 | 
						|
            if !r.has_file("pdf") {
 | 
						|
                r.bad_request("Missing PDF in 'pdf'!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            let file = r.save_post_pdf("pdf", PATH_POST_PDF)?;
 | 
						|
 | 
						|
            PostKind::POST_KIND_PDF(PostFile::new_from_created_file(&file)?)
 | 
						|
        }
 | 
						|
 | 
						|
        "countdown" => {
 | 
						|
            let time_end = r.post_u64("time-end")?;
 | 
						|
 | 
						|
            if time_end < time() {
 | 
						|
                r.bad_request("You can not create countdown timer for past events!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            PostKind::POST_KIND_COUNTDOWN(time_end)
 | 
						|
        }
 | 
						|
 | 
						|
        "survey" => {
 | 
						|
            let survey = NewSurvey {
 | 
						|
                post_id: 0,
 | 
						|
                user_id: r.user_id()?,
 | 
						|
                question: r.post_string("question")?,
 | 
						|
                choices: r
 | 
						|
                    .post_string("answers")?
 | 
						|
                    .split("<>")
 | 
						|
                    .filter(|a| a.len() > 0)
 | 
						|
                    .map(|a| a.to_string())
 | 
						|
                    .collect(),
 | 
						|
                allow_new_choices: r.post_bool_opt("allowNewAnswers", false),
 | 
						|
            };
 | 
						|
 | 
						|
            if survey.choices.len() < 2 {
 | 
						|
                r.bad_request("A survey must have at least two choices!".to_string())?;
 | 
						|
            }
 | 
						|
 | 
						|
            new_survey = Some(survey);
 | 
						|
            PostKind::POST_KIND_SURVEY
 | 
						|
        }
 | 
						|
 | 
						|
        _ => {
 | 
						|
            r.internal_error(ExecError::boxed_new("Unsupported kind of post!"))?;
 | 
						|
            unreachable!();
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // Create the post
 | 
						|
    let post_id = posts_helper::create(&post)?;
 | 
						|
 | 
						|
    // Create associated survey, if required
 | 
						|
    if let Some(mut survey) = new_survey {
 | 
						|
        survey.post_id = post_id;
 | 
						|
        survey_helper::create(&survey)?;
 | 
						|
    }
 | 
						|
 | 
						|
    // Create a notification
 | 
						|
    notifications_helper::create_post_notification(
 | 
						|
        r.user_id_ref()?,
 | 
						|
        post_id,
 | 
						|
        NotifEventType::ELEM_CREATED,
 | 
						|
    )
 | 
						|
    .await?;
 | 
						|
 | 
						|
    r.set_response(ResCreatePost::new(post_id))
 | 
						|
}
 | 
						|
 | 
						|
/// Change the visibility level of a post
 | 
						|
pub async fn set_visibility_level(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let post = r.post_post_with_access("postID", PostAccessLevel::FULL_ACCESS)?;
 | 
						|
    let new_visibility = PostVisibilityLevel::from_api(&r.post_string("new_level")?);
 | 
						|
 | 
						|
    posts_helper::set_level(post.id, &new_visibility)?;
 | 
						|
 | 
						|
    // Depending on new level, delete (or not) notifications about the post
 | 
						|
    if matches!(new_visibility, PostVisibilityLevel::VISIBILITY_USER) {
 | 
						|
        notifications_helper::delete_all_related_with_post(post.id).await?;
 | 
						|
    }
 | 
						|
 | 
						|
    r.success("Visibility level updated")
 | 
						|
}
 | 
						|
 | 
						|
/// Update the content of a post
 | 
						|
pub async fn update_content(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let post = r.post_post_with_access("postID", PostAccessLevel::FULL_ACCESS)?;
 | 
						|
    let new_content = r.post_content("new_content", 2, true)?;
 | 
						|
 | 
						|
    posts_helper::set_content(post.id, &new_content)?;
 | 
						|
 | 
						|
    // Delete the notifications targeting the current user about this post
 | 
						|
    notifications_helper::delete_all_post_notifications_targeting_user(r.user_id_ref()?, post.id)
 | 
						|
        .await?;
 | 
						|
 | 
						|
    r.success("Content updated")
 | 
						|
}
 | 
						|
 | 
						|
/// Delete a post
 | 
						|
pub async fn delete(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let post = r.post_post_with_access("postID", PostAccessLevel::INTERMEDIATE_ACCESS)?;
 | 
						|
 | 
						|
    posts_helper::delete(&post).await?;
 | 
						|
 | 
						|
    r.success("Post deleted.")
 | 
						|
}
 | 
						|
 | 
						|
/// Get the list of targets where the current user can create posts
 | 
						|
pub async fn get_targets(r: &mut HttpRequestHandler) -> RequestResult {
 | 
						|
    let friends = friends_helper::get_list_that_allow_posts_from_user(r.user_id_ref()?)?;
 | 
						|
    let groups = groups_helper::get_list_where_user_can_create_posts(r.user_id_ref()?)?;
 | 
						|
 | 
						|
    r.set_response(PostsTargets::new(&friends, &groups))
 | 
						|
}
 |