mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 01:24:04 +00:00 
			
		
		
		
	Add survey posts support
This commit is contained in:
		@@ -32,3 +32,5 @@ pub mod friend_api;
 | 
			
		||||
pub mod friendship_status_api;
 | 
			
		||||
pub mod post_api;
 | 
			
		||||
pub mod movie_api;
 | 
			
		||||
pub mod survey_choice_api;
 | 
			
		||||
pub mod survey_api;
 | 
			
		||||
@@ -4,10 +4,11 @@
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
 | 
			
		||||
use crate::api_data::movie_api::MovieAPI;
 | 
			
		||||
use crate::api_data::survey_api::SurveyAPI;
 | 
			
		||||
use crate::data::error::ResultBoxError;
 | 
			
		||||
use crate::data::post::{Post, PostKind};
 | 
			
		||||
use crate::data::user::UserID;
 | 
			
		||||
use crate::helpers::movies_helper;
 | 
			
		||||
use crate::helpers::{movies_helper, survey_helper};
 | 
			
		||||
use crate::utils::user_data_utils::user_data_url;
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
@@ -40,11 +41,14 @@ pub struct PostAPI {
 | 
			
		||||
 | 
			
		||||
    // Countdown timer specific
 | 
			
		||||
    time_end: Option<u64>,
 | 
			
		||||
 | 
			
		||||
    // Survey specific
 | 
			
		||||
    data_survey: Option<SurveyAPI>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PostAPI {
 | 
			
		||||
    /// Turn a `Post` entry into an API entry
 | 
			
		||||
    pub fn new(p: &Post) -> ResultBoxError<PostAPI> {
 | 
			
		||||
    pub fn new(p: &Post, user: &Option<UserID>) -> ResultBoxError<PostAPI> {
 | 
			
		||||
        let mut post = PostAPI {
 | 
			
		||||
            ID: p.id,
 | 
			
		||||
            userID: p.user_id.id(),
 | 
			
		||||
@@ -73,6 +77,9 @@ impl PostAPI {
 | 
			
		||||
 | 
			
		||||
            // Countdown timer-specific
 | 
			
		||||
            time_end: None,
 | 
			
		||||
 | 
			
		||||
            // Survey specific
 | 
			
		||||
            data_survey: None,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        match &p.kind {
 | 
			
		||||
@@ -99,7 +106,9 @@ impl PostAPI {
 | 
			
		||||
 | 
			
		||||
            PostKind::POST_KIND_COUNTDOWN(time_end) => post.time_end = Some(*time_end),
 | 
			
		||||
 | 
			
		||||
            PostKind::POST_KIND_SURVEY => {}
 | 
			
		||||
            PostKind::POST_KIND_SURVEY =>
 | 
			
		||||
                post.data_survey = Some(SurveyAPI::new(&survey_helper::get_info(p.id)?, user.clone())?),
 | 
			
		||||
 | 
			
		||||
            PostKind::POST_KIND_YOUTUBE => {}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -107,7 +116,7 @@ impl PostAPI {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Turn a list of posts into an API entry
 | 
			
		||||
    pub fn for_list(l: &Vec<Post>) -> ResultBoxError<Vec<PostAPI>> {
 | 
			
		||||
        l.iter().map(Self::new).collect()
 | 
			
		||||
    pub fn for_list(l: &Vec<Post>, user_id: Option<UserID>) -> ResultBoxError<Vec<PostAPI>> {
 | 
			
		||||
        l.iter().map(|p| Self::new(p, &user_id)).collect()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/api_data/survey_api.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/api_data/survey_api.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
//! # Survey API information
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
 | 
			
		||||
use crate::api_data::survey_choice_api::SurveyChoiceAPI;
 | 
			
		||||
use crate::data::error::ResultBoxError;
 | 
			
		||||
use crate::data::survey::Survey;
 | 
			
		||||
use crate::data::user::UserID;
 | 
			
		||||
use crate::helpers::survey_helper;
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
#[allow(non_snake_case)]
 | 
			
		||||
pub struct SurveyAPI {
 | 
			
		||||
    ID: u64,
 | 
			
		||||
    userID: u64,
 | 
			
		||||
    postID: u64,
 | 
			
		||||
    creation_time: u64,
 | 
			
		||||
    question: String,
 | 
			
		||||
    user_choice: u64,
 | 
			
		||||
    choices: HashMap<u64, SurveyChoiceAPI>,
 | 
			
		||||
    allowNewChoices: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SurveyAPI {
 | 
			
		||||
    /// Create a new survey API entry
 | 
			
		||||
    pub fn new(s: &Survey, curr_user_id: Option<UserID>) -> ResultBoxError<SurveyAPI> {
 | 
			
		||||
        let user_choice = match &curr_user_id {
 | 
			
		||||
            None => 0, /* -1 is not possible */
 | 
			
		||||
            Some(user_id) => survey_helper::get_user_choice(s.id, user_id)?,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Ok(SurveyAPI {
 | 
			
		||||
            ID: s.id,
 | 
			
		||||
            userID: s.user_id.id(),
 | 
			
		||||
            postID: s.post_id,
 | 
			
		||||
            creation_time: s.time_create,
 | 
			
		||||
            question: s.question.clone(),
 | 
			
		||||
            user_choice,
 | 
			
		||||
            choices: SurveyChoiceAPI::for_list(&s.choices),
 | 
			
		||||
            allowNewChoices: s.allow_new_choices,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								src/api_data/survey_choice_api.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/api_data/survey_choice_api.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
//! # Survey choice API
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
 | 
			
		||||
use crate::data::survey::SurveyChoice;
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
#[allow(non_snake_case)]
 | 
			
		||||
pub struct SurveyChoiceAPI {
 | 
			
		||||
    choiceID: u64,
 | 
			
		||||
    name: String,
 | 
			
		||||
    responses: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SurveyChoiceAPI {
 | 
			
		||||
    pub fn new(c: &SurveyChoice) -> SurveyChoiceAPI {
 | 
			
		||||
        SurveyChoiceAPI {
 | 
			
		||||
            choiceID: c.id,
 | 
			
		||||
            name: c.name.clone(),
 | 
			
		||||
            responses: c.count,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn for_list(c: &Vec<SurveyChoice>) -> HashMap<u64, SurveyChoiceAPI> {
 | 
			
		||||
        let mut map = HashMap::with_capacity(c.len());
 | 
			
		||||
        c.iter().for_each(|c| { map.insert(c.id, Self::new(c)); });
 | 
			
		||||
        map
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -40,6 +40,15 @@ pub mod database_tables_names {
 | 
			
		||||
 | 
			
		||||
    /// Movies table
 | 
			
		||||
    pub const MOVIES_TABLE: &str = "galerie_video";
 | 
			
		||||
 | 
			
		||||
    /// Survey info table
 | 
			
		||||
    pub const SURVEY_INFO_TABLE: &str = "sondage";
 | 
			
		||||
 | 
			
		||||
    /// Survey choices table
 | 
			
		||||
    pub const SURVEY_CHOICES_TABLE: &str = "sondage_choix";
 | 
			
		||||
 | 
			
		||||
    /// Survey responses table
 | 
			
		||||
    pub const SURVEY_RESPONSE_TABLE: &str = "sondage_reponse";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The account image to show for user who do not have any
 | 
			
		||||
 
 | 
			
		||||
@@ -20,5 +20,5 @@ pub fn get_list_user(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
        .set_start_from(start_from)
 | 
			
		||||
        .get_user(&user_id)?;
 | 
			
		||||
 | 
			
		||||
    r.set_response(PostAPI::for_list(&posts)?)
 | 
			
		||||
    r.set_response(PostAPI::for_list(&posts, r.user_id_opt())?)
 | 
			
		||||
}
 | 
			
		||||
@@ -21,3 +21,4 @@ pub mod friend;
 | 
			
		||||
pub mod friendship_status;
 | 
			
		||||
pub mod post;
 | 
			
		||||
pub mod movie;
 | 
			
		||||
pub mod survey;
 | 
			
		||||
							
								
								
									
										23
									
								
								src/data/survey.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/data/survey.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
//! # Survey
 | 
			
		||||
//!
 | 
			
		||||
//! This structure contains all the information about a survey
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use crate::data::user::UserID;
 | 
			
		||||
 | 
			
		||||
pub struct SurveyChoice {
 | 
			
		||||
    pub id: u64,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub count: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Survey {
 | 
			
		||||
    pub id: u64,
 | 
			
		||||
    pub user_id: UserID,
 | 
			
		||||
    pub time_create: u64,
 | 
			
		||||
    pub post_id: u64,
 | 
			
		||||
    pub question: String,
 | 
			
		||||
    pub choices: Vec<SurveyChoice>,
 | 
			
		||||
    pub allow_new_choices: bool,
 | 
			
		||||
}
 | 
			
		||||
@@ -51,6 +51,13 @@ pub fn get_connection() -> Result<mysql::PooledConn, Box<dyn Error>> {
 | 
			
		||||
    Ok(pool.get_conn()?)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Join type
 | 
			
		||||
#[derive(PartialEq)]
 | 
			
		||||
pub enum DatabaseQueryJoinType {
 | 
			
		||||
    NORMAL,
 | 
			
		||||
    LEFT,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Structure used to implement JOIN on queries
 | 
			
		||||
struct QueryJoin {
 | 
			
		||||
    table: String,
 | 
			
		||||
@@ -64,6 +71,7 @@ pub struct QueryInfo {
 | 
			
		||||
    pub table_alias: Option<String>,
 | 
			
		||||
 | 
			
		||||
    /// Joins
 | 
			
		||||
    joins_type: DatabaseQueryJoinType,
 | 
			
		||||
    joins: Vec<QueryJoin>,
 | 
			
		||||
 | 
			
		||||
    /// Query limits
 | 
			
		||||
@@ -75,6 +83,9 @@ pub struct QueryInfo {
 | 
			
		||||
    /// Custom WHERE values
 | 
			
		||||
    pub custom_where_ars: Vec<mysql::Value>,
 | 
			
		||||
 | 
			
		||||
    /// Custom GROUP BY argument
 | 
			
		||||
    group_by: Option<String>,
 | 
			
		||||
 | 
			
		||||
    /// Limit of the query (0 = no limit)
 | 
			
		||||
    pub limit: u64,
 | 
			
		||||
 | 
			
		||||
@@ -93,10 +104,12 @@ impl QueryInfo {
 | 
			
		||||
        QueryInfo {
 | 
			
		||||
            table: table.to_string(),
 | 
			
		||||
            table_alias: None,
 | 
			
		||||
            joins_type: DatabaseQueryJoinType::NORMAL,
 | 
			
		||||
            joins: Vec::new(),
 | 
			
		||||
            conditions: collections::HashMap::new(),
 | 
			
		||||
            custom_where: None,
 | 
			
		||||
            custom_where_ars: vec![],
 | 
			
		||||
            group_by: None,
 | 
			
		||||
            limit: 0,
 | 
			
		||||
            order: None,
 | 
			
		||||
            fields: Vec::new(),
 | 
			
		||||
@@ -109,6 +122,12 @@ impl QueryInfo {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set join type
 | 
			
		||||
    pub fn set_join_type(mut self, t: DatabaseQueryJoinType) -> QueryInfo {
 | 
			
		||||
        self.joins_type = t;
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn join(mut self, table: &str, table_alias: &str, cond: &str) -> QueryInfo {
 | 
			
		||||
        self.joins.push(QueryJoin {
 | 
			
		||||
            table: table.to_string(),
 | 
			
		||||
@@ -194,9 +213,9 @@ impl QueryInfo {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set the limit for the request
 | 
			
		||||
    pub fn set_limit(mut self, value: u64) -> QueryInfo {
 | 
			
		||||
        self.limit = value;
 | 
			
		||||
    /// Set GROUP BY clause
 | 
			
		||||
    pub fn set_group_by(mut self, group_by: &str) -> QueryInfo {
 | 
			
		||||
        self.group_by = Some(group_by.to_string());
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -206,6 +225,12 @@ impl QueryInfo {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set the limit for the request
 | 
			
		||||
    pub fn set_limit(mut self, value: u64) -> QueryInfo {
 | 
			
		||||
        self.limit = value;
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Execute query
 | 
			
		||||
    pub fn exec<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(self, process_function: F)
 | 
			
		||||
                                                             -> Result<Vec<E>, Box<dyn Error>> {
 | 
			
		||||
@@ -396,6 +421,10 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Join conditions
 | 
			
		||||
    if info.joins_type == DatabaseQueryJoinType::LEFT {
 | 
			
		||||
        query.push_str(" LEFT ");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for j in info.joins {
 | 
			
		||||
        query = query.add(
 | 
			
		||||
            format!(" JOIN {} {} ON {} ", j.table, j.table_alias, j.condition).as_ref());
 | 
			
		||||
@@ -427,6 +456,11 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
 | 
			
		||||
        params.append(&mut custom_args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // GROUP BY clause
 | 
			
		||||
    if let Some(group_by) = info.group_by {
 | 
			
		||||
        query.push_str(format!(" GROUP BY {} ", group_by).as_str())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ORDER clause
 | 
			
		||||
    if let Some(order) = info.order {
 | 
			
		||||
        query = query.add(format!(" ORDER BY {} ", order).as_str());
 | 
			
		||||
 
 | 
			
		||||
@@ -12,3 +12,4 @@ pub mod posts_helper;
 | 
			
		||||
pub mod conversations_helper;
 | 
			
		||||
pub mod virtual_directory_helper;
 | 
			
		||||
pub mod movies_helper;
 | 
			
		||||
pub mod survey_helper;
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
use crate::constants::database_tables_names::POSTS_TABLE;
 | 
			
		||||
use crate::data::error::{ExecError, ResultBoxError};
 | 
			
		||||
use crate::data::post::{Post, PostFile, PostKind, PostPageKind, PostVisibilityLevel, PostWebLink};
 | 
			
		||||
use crate::data::post::PostKind::{POST_KIND_COUNTDOWN, POST_KIND_IMAGE, POST_KIND_MOVIE, POST_KIND_PDF, POST_KIND_WEBLINK};
 | 
			
		||||
use crate::data::post::PostKind::{POST_KIND_COUNTDOWN, POST_KIND_IMAGE, POST_KIND_MOVIE, POST_KIND_PDF, POST_KIND_SURVEY, POST_KIND_WEBLINK};
 | 
			
		||||
use crate::data::user::UserID;
 | 
			
		||||
use crate::helpers::{database, friends_helper};
 | 
			
		||||
use crate::utils::date_utils::time;
 | 
			
		||||
@@ -174,6 +174,8 @@ fn db_to_post(res: &database::RowResult) -> ResultBoxError<Post> {
 | 
			
		||||
 | 
			
		||||
        "count_down" => post.kind = POST_KIND_COUNTDOWN(res.get_u64("time_end").unwrap_or(0)),
 | 
			
		||||
 | 
			
		||||
        "sondage" => post.kind = POST_KIND_SURVEY,
 | 
			
		||||
 | 
			
		||||
        _ => {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								src/helpers/survey_helper.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/helpers/survey_helper.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
//! # Survey helper
 | 
			
		||||
//!
 | 
			
		||||
//! @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
use crate::constants::database_tables_names::{SURVEY_CHOICES_TABLE, SURVEY_INFO_TABLE, SURVEY_RESPONSE_TABLE};
 | 
			
		||||
use crate::data::error::ResultBoxError;
 | 
			
		||||
use crate::data::survey::{Survey, SurveyChoice};
 | 
			
		||||
use crate::data::user::UserID;
 | 
			
		||||
use crate::helpers::database;
 | 
			
		||||
 | 
			
		||||
/// Get information about a survey
 | 
			
		||||
pub fn get_info(post_id: u64) -> ResultBoxError<Survey> {
 | 
			
		||||
    database::QueryInfo::new(SURVEY_INFO_TABLE)
 | 
			
		||||
        .cond_u64("ID_texte", post_id)
 | 
			
		||||
        .query_row(db_to_survey)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the choices of a survey
 | 
			
		||||
fn get_survey_choices(survey_id: u64) -> ResultBoxError<Vec<SurveyChoice>> {
 | 
			
		||||
    database::QueryInfo::new(SURVEY_CHOICES_TABLE)
 | 
			
		||||
        .alias("c")
 | 
			
		||||
        .set_join_type(database::DatabaseQueryJoinType::LEFT)
 | 
			
		||||
        .join(SURVEY_RESPONSE_TABLE, "r", "c.ID = r.ID_sondage_choix")
 | 
			
		||||
        .cond_u64("c.ID_sondage", survey_id)
 | 
			
		||||
        .set_group_by("c.ID")
 | 
			
		||||
        .add_field("c.*")
 | 
			
		||||
        .add_field("COUNT(r.ID) AS count_choice")
 | 
			
		||||
        .exec(db_to_survey_choice)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the choice of a user for a survey
 | 
			
		||||
pub fn get_user_choice(survey_id: u64, user_id: &UserID) -> ResultBoxError<u64> {
 | 
			
		||||
    Ok(database::QueryInfo::new(SURVEY_RESPONSE_TABLE)
 | 
			
		||||
        .cond_u64("ID_sondage", survey_id)
 | 
			
		||||
        .cond_user_id("ID_utilisateurs", user_id)
 | 
			
		||||
        .exec(|r| r.get_u64("ID_sondage_choix"))?
 | 
			
		||||
        .pop()
 | 
			
		||||
        .unwrap_or(0))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Turn a database entry into a row object
 | 
			
		||||
fn db_to_survey(row: &database::RowResult) -> ResultBoxError<Survey> {
 | 
			
		||||
    let survey_id = row.get_u64("ID")?;
 | 
			
		||||
 | 
			
		||||
    Ok(Survey {
 | 
			
		||||
        id: survey_id,
 | 
			
		||||
        user_id: row.get_user_id("ID_utilisateurs")?,
 | 
			
		||||
        time_create: row.get_date_as_time("date_creation")?,
 | 
			
		||||
        post_id: row.get_u64("ID_texte")?,
 | 
			
		||||
        question: row.get_str("question")?,
 | 
			
		||||
        choices: get_survey_choices(survey_id)?,
 | 
			
		||||
        allow_new_choices: row.get_legacy_bool("allow_new_choices")?,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Turn a database row into a survey choice
 | 
			
		||||
fn db_to_survey_choice(row: &database::RowResult) -> ResultBoxError<SurveyChoice> {
 | 
			
		||||
    Ok(SurveyChoice {
 | 
			
		||||
        id: row.get_u64("ID")?,
 | 
			
		||||
        name: row.get_str("Choix")?,
 | 
			
		||||
        count: row.get_u64("count_choice")?,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user