From 664824ff481dc63bb1f8582099a40f953af04a26 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Sun, 14 Feb 2021 16:45:00 +0100 Subject: [PATCH] Automatically clean old likes --- src/cleanup_thread.rs | 12 +++- src/data/user.rs | 8 +++ src/helpers/database.rs | 44 +++++++++++++-- src/helpers/likes_helper.rs | 19 ++++++- src/helpers/user_helper.rs | 106 ++++++++++++++++++++---------------- 5 files changed, 134 insertions(+), 55 deletions(-) diff --git a/src/cleanup_thread.rs b/src/cleanup_thread.rs index 7f294f3..e8d3b2e 100644 --- a/src/cleanup_thread.rs +++ b/src/cleanup_thread.rs @@ -6,7 +6,7 @@ use crate::constants::CLEAN_UP_INTERVAL; use crate::data::error::Res; -use crate::helpers::account_helper; +use crate::helpers::{account_helper, user_helper, likes_helper}; /// Start the maintenance thread pub fn start() -> Res { @@ -38,5 +38,15 @@ fn do_clean() -> Res { // Clean old login tokens account_helper::clean_up_old_access_tokens()?; + // Automatic account cleanup + for user in user_helper::get_all_users()? { + + // Clean old likes + likes_helper::clean_old_user_likes(&user)?; + + + } + + Ok(()) } \ No newline at end of file diff --git a/src/data/user.rs b/src/data/user.rs index f252583..f9455f9 100644 --- a/src/data/user.rs +++ b/src/data/user.rs @@ -120,6 +120,14 @@ pub struct User { pub security_answer_1: Option, pub security_question_2: Option, pub security_answer_2: Option, + + /// Automatically delete the account after a period of inactivity. 0 = feature disabled + pub delete_account_after: u64, + pub delete_notifications_after: u64, + pub delete_comments_after: u64, + pub delete_posts_after: u64, + pub delete_conversation_messages_after: u64, + pub delete_likes_after: u64, } impl User { diff --git a/src/helpers/database.rs b/src/helpers/database.rs index c40030e..460bce5 100644 --- a/src/helpers/database.rs +++ b/src/helpers/database.rs @@ -662,6 +662,8 @@ pub fn insert(query: InsertQuery) -> ResultBoxError> { pub struct DeleteQuery { table: String, conditions: HashMap, + custom_where: Option, + custom_where_args: Vec, } impl DeleteQuery { @@ -670,9 +672,28 @@ impl DeleteQuery { DeleteQuery { table: table.to_string(), conditions: HashMap::new(), + custom_where: None, + custom_where_args: vec![], } } + pub fn set_custom_where(mut self, cond: &str) -> Self { + self.custom_where = Some(cond.to_string()); + self + } + + /// Add custom WHERE argument + pub fn add_custom_where_arg_u64(mut self, arg: u64) -> Self { + self.custom_where_args.push(mysql::Value::UInt(arg)); + self + } + + /// Add custom WHERE argument + pub fn add_custom_where_arg_str(mut self, arg: &str) -> Self { + self.custom_where_args.push(mysql::Value::from(arg)); + self + } + /// Add batch conditions pub fn add_conditions(mut self, conditions: HashMap) -> Self { self.conditions.extend(conditions.into_iter()); @@ -732,7 +753,7 @@ pub fn delete(query: DeleteQuery) -> ResultBoxError<()> { return Err(ExecError::boxed_new("DELETE without WHERE condition blocked for security reasons!")); } - let query_sql = format!( + let mut query_sql = format!( "DELETE FROM {} WHERE {}", query.table, query.conditions.keys() @@ -741,10 +762,23 @@ pub fn delete(query: DeleteQuery) -> ResultBoxError<()> { .join(" AND ") ); - get_connection()?.exec_drop( - query_sql, - query.conditions.values().collect::>(), - )?; + let mut values = query.conditions.values().collect::>(); + + if let Some(custom_where) = &query.custom_where { + if !query.conditions.is_empty() { + query_sql.push_str(" AND "); + } + + query_sql.push_str("("); + query_sql.push_str(custom_where); + query_sql.push_str(")"); + + for value in &query.custom_where_args { + values.push(value); + } + } + + get_connection()?.exec_drop(query_sql, values)?; Ok(()) } diff --git a/src/helpers/likes_helper.rs b/src/helpers/likes_helper.rs index f73a147..6b7ebc6 100644 --- a/src/helpers/likes_helper.rs +++ b/src/helpers/likes_helper.rs @@ -3,12 +3,12 @@ //! Module dedicated to likes management use crate::constants::database_tables_names::LIKES_TABLE; -use crate::data::error::ResultBoxError; -use crate::data::user::UserID; +use crate::data::error::{Res, ResultBoxError}; +use crate::data::user::{User, UserID}; use crate::data::user_like::UserLike; use crate::helpers::database; use crate::helpers::database::QueryInfo; -use crate::utils::date_utils::mysql_date; +use crate::utils::date_utils::{mysql_date, time, time_to_mysql_date}; #[derive(Copy, Clone)] pub enum LikeType { @@ -96,6 +96,19 @@ pub fn delete_all_user(user_id: &UserID) -> ResultBoxError { .exec() } +/// Delete old user likes +pub fn clean_old_user_likes(user: &User) -> Res { + if user.delete_likes_after < 1 { + return Ok(()); + } + + database::DeleteQuery::new(LIKES_TABLE) + .cond_user_id("ID_personne", &user.id) + .set_custom_where("Date_envoi < ?") + .add_custom_where_arg_str(&time_to_mysql_date(time() - user.delete_likes_after)) + .exec() +} + /// Turn a database entry into a like entry fn db_to_user_like(r: &database::RowResult) -> ResultBoxError { Ok(UserLike { diff --git a/src/helpers/user_helper.rs b/src/helpers/user_helper.rs index 9519b7d..293fe38 100644 --- a/src/helpers/user_helper.rs +++ b/src/helpers/user_helper.rs @@ -1,5 +1,5 @@ use crate::constants::database_tables_names::USERS_TABLE; -use crate::data::error::ResultBoxError; +use crate::data::error::{Res, ResultBoxError}; use crate::data::user::{AccountImageVisibility, User, UserID, UserPageStatus}; use crate::data::user::UserPageStatus::PUBLIC; use crate::helpers::{database, friends_helper}; @@ -11,65 +11,79 @@ use crate::helpers::friends_helper::are_friend; /// Get & return information about a user based on its ID pub fn find_user_by_id(id: &UserID) -> ResultBoxError { - exec_get_user_query( - database::QueryInfo::new(USERS_TABLE).cond_user_id("ID", id)) + database::QueryInfo::new(USERS_TABLE) + .cond_user_id("ID", id) + .query_row(db_to_user) } /// Get & return information about a user based on his email pub fn find_user_by_email(email: &str) -> ResultBoxError { - exec_get_user_query( - database::QueryInfo::new(USERS_TABLE).cond("mail", email)) + database::QueryInfo::new(USERS_TABLE) + .cond("mail", email) + .query_row(db_to_user) } /// Get & return information about a user based on his virtual directory pub fn find_user_by_virtual_directory(dir: &str) -> ResultBoxError { - exec_get_user_query( - database::QueryInfo::new(USERS_TABLE).cond("sous_repertoire", dir)) + database::QueryInfo::new(USERS_TABLE) + .cond("sous_repertoire", dir) + .query_row(db_to_user) +} + +/// Get the entire list of Comunic users +pub fn get_all_users() -> Res> { + database::QueryInfo::new(USERS_TABLE) + .exec(db_to_user) } /// Execute query & return result -fn exec_get_user_query(query: database::QueryInfo) -> ResultBoxError { - database::query_row(query, |res| { +fn db_to_user(res: &database::RowResult) -> ResultBoxError { - // Page status - let page_status = if res.get_int64("pageouverte")? == 1 { - UserPageStatus::OPEN - } else if res.get_int64("public")? == 1 { - UserPageStatus::PUBLIC - } else { - UserPageStatus::PRIVATE - }; - // Account image visibility - let account_image_visibility = match res.get_str("account_image_visibility")?.as_ref() { - "friends" => AccountImageVisibility::FRIENDS, - "comunic_users" => AccountImageVisibility::COMUNIC_USERS, - "everyone" | _ => AccountImageVisibility::EVERYONE, - }; + // Page status + let page_status = if res.get_int64("pageouverte")? == 1 { + UserPageStatus::OPEN + } else if res.get_int64("public")? == 1 { + UserPageStatus::PUBLIC + } else { + UserPageStatus::PRIVATE + }; - Ok(User { - id: res.get_user_id("ID")?, - email: res.get_str("mail")?, - password: res.get_str("password")?, - first_name: res.get_str("prenom")?, - last_name: res.get_str("nom")?, - status: page_status, - virtual_directory: res.get_optional_str("sous_repertoire")?, - account_image_path: res.get_optional_str("account_image_path")?, - account_image_visibility, - public_friends_list: res.get_legacy_bool("liste_amis_publique")?, - personal_website: res.get_optional_str("site_web")?, - public_note: res.get_optional_str("public_note")?, - block_comments_on_his_page: res.get_legacy_bool("bloquecommentaire")?, - allow_posts_from_friends: res.get_legacy_bool("autoriser_post_amis")?, - account_creation_time: res.get_date_as_time("date_creation")?, - allow_mails: res.get_legacy_bool("autorise_mail")?, - lang: res.get_str("lang")?, - security_question_1: res.get_optional_str("question1")?, - security_answer_1: res.get_optional_str("reponse1")?, - security_question_2: res.get_optional_str("question2")?, - security_answer_2: res.get_optional_str("reponse2")?, - }) + // Account image visibility + let account_image_visibility = match res.get_str("account_image_visibility")?.as_ref() { + "friends" => AccountImageVisibility::FRIENDS, + "comunic_users" => AccountImageVisibility::COMUNIC_USERS, + "everyone" | _ => AccountImageVisibility::EVERYONE, + }; + + Ok(User { + id: res.get_user_id("ID")?, + email: res.get_str("mail")?, + password: res.get_str("password")?, + first_name: res.get_str("prenom")?, + last_name: res.get_str("nom")?, + status: page_status, + virtual_directory: res.get_optional_str("sous_repertoire")?, + account_image_path: res.get_optional_str("account_image_path")?, + account_image_visibility, + public_friends_list: res.get_legacy_bool("liste_amis_publique")?, + personal_website: res.get_optional_str("site_web")?, + public_note: res.get_optional_str("public_note")?, + block_comments_on_his_page: res.get_legacy_bool("bloquecommentaire")?, + allow_posts_from_friends: res.get_legacy_bool("autoriser_post_amis")?, + account_creation_time: res.get_date_as_time("date_creation")?, + allow_mails: res.get_legacy_bool("autorise_mail")?, + lang: res.get_str("lang")?, + security_question_1: res.get_optional_str("question1")?, + security_answer_1: res.get_optional_str("reponse1")?, + security_question_2: res.get_optional_str("question2")?, + security_answer_2: res.get_optional_str("reponse2")?, + delete_account_after: res.get_u64("delete_account_after")?, + delete_notifications_after: res.get_u64("delete_notifications_after")?, + delete_comments_after: res.get_u64("delete_comments_after")?, + delete_posts_after: res.get_u64("delete_posts_after")?, + delete_conversation_messages_after: res.get_u64("delete_conversation_messages_after")?, + delete_likes_after: res.get_u64("delete_likes_after")?, }) }