diff --git a/src/command_line_runner.rs b/src/command_line_runner.rs index 95e0edf8..6f7e0dd3 100644 --- a/src/command_line_runner.rs +++ b/src/command_line_runner.rs @@ -3,12 +3,18 @@ use std::io::{Error, ErrorKind, stdin, stdout, Write}; use std::process::exit; use std::str::FromStr; use log::error; -use sha256::digest; +use sha256::{digest}; use crate::config::dbconfig::establish_connection; use crate::constants::constants::Role; use crate::models::user::{User, UserWithoutPassword}; use crate::utils::time::get_current_timestamp_str; use rpassword::read_password; +use crate::models::device::Device; +use crate::models::episode::Episode; +use crate::models::favorites::Favorite; +use crate::models::models::PodcastHistoryItem; +use crate::models::session::Session; +use crate::models::subscription::Subscription; pub fn start_command_line(mut args: Args){ @@ -55,9 +61,45 @@ pub fn start_command_line(mut args: Args){ println!("{}", username); match available_users.iter().find(|u|u.username==username){ Some(..)=>{ - User::delete_by_username(trim_string(username), + PodcastHistoryItem::delete_by_username(trim_string(username.clone()), + &mut establish_connection()) + .expect("Error deleting entries for podcast history item"); + Device::delete_by_username(username.clone(), &mut + establish_connection()) + .expect("Error deleting devices"); + Episode::delete_by_username_and_episode(trim_string(username.clone()), + &mut establish_connection()) + .expect("Error deleting episodes"); + Favorite::delete_by_username(trim_string(username.clone()), + &mut establish_connection()) + .expect("Error deleting favorites"); + Session::delete_by_username(&trim_string(username.clone()), + &mut establish_connection()) + .expect("Error deleting sessions"); + Subscription::delete_by_username(&trim_string(username.clone()), + &mut establish_connection()).expect("TODO: panic message"); + User::delete_by_username(trim_string(username.clone()), &mut establish_connection()) .expect("Error deleting user"); + println!("User deleted") + }, + None=>{ + println!("Username not found") + } + } + } + "update"=>{ + //update a user + list_users(); + let mut username = String::new(); + + retry_read("Please enter the username of the user you want to delete", + &mut username); + username = trim_string(username); + println!(">{}<", username); + match User::find_by_username(username.as_str(), &mut establish_connection()){ + Some(user)=>{ + do_user_update(user) }, None=>{ println!("Username not found") @@ -119,9 +161,9 @@ pub fn read_user_account()->User{ let user = User{ id: 0, - username: username.trim_end_matches("\n").parse().unwrap(), + username: trim_string(username.clone()), role: assigned_role.to_string(), - password: Some(password.trim_end_matches("\n").parse().unwrap()), + password: Some(trim_string(password)), explicit_consent: false, created_at: get_current_timestamp_str(), }; @@ -148,15 +190,15 @@ pub fn retry_read(prompt: &str, input: &mut String){ pub fn retry_read_secret(prompt: &str)->String{ println!("{}",prompt); stdout().flush().unwrap(); - let mut input = read_password().unwrap(); + let input = read_password().unwrap(); match input.len()>0{ true => { if input.trim().len()==0{ - retry_read(prompt, &mut input); + retry_read_secret(prompt); } } false => { - retry_read(prompt, &mut input); + retry_read_secret(prompt); } } input @@ -166,7 +208,7 @@ pub fn retry_read_role(prompt: &str)->Role{ let mut input = String::new(); println!("{}",prompt); stdin().read_line(&mut input).unwrap(); - let res = Role::from_str(input.as_str().trim_end_matches("\n")); + let res = Role::from_str(&trim_string(input)); match res{ Err(..)=> { println!("Error setting role. Please choose one of the possible roles."); @@ -190,5 +232,42 @@ fn ask_for_confirmation()->Result<(),Error>{ fn trim_string(string_to_trim: String)->String{ - string_to_trim.trim_end_matches("\n").parse().unwrap() + string_to_trim.trim_end_matches("\n").trim().parse().unwrap() +} + + +fn do_user_update(mut user:User){ + let mut input = String::new(); + println!("The following settings of a user should be updated: {:?}",user); + println!("Enter which field of a user should be updated [role, password, \ + explicit_consent]"); + stdin().read_line(&mut input) + .expect("Error reading from terminal"); + input = trim_string(input); + match input.as_str() { + "role" =>{ + user.role = Role::to_string(&retry_read_role("Enter the new role [user,admin]")); + User::update_user(user, &mut establish_connection()) + .expect("Error updating role"); + println!("Role updated"); + }, + "password"=>{ + let mut password = retry_read_secret("Enter the new username"); + password = digest(password); + user.password = Some(password); + User::update_user(user, &mut establish_connection()) + .expect("Error updating username"); + println!("Password updated"); + }, + "explicit_consent"=>{ + user.explicit_consent = !user.explicit_consent; + User::update_user(user, &mut establish_connection()) + .expect("Error updating explicit_consent"); + println!("Explicit consent updated"); + } + _=>{ + println!("Field not found"); + } + } + } \ No newline at end of file diff --git a/src/models/device.rs b/src/models/device.rs index 1db56b9e..a702a40d 100644 --- a/src/models/device.rs +++ b/src/models/device.rs @@ -59,4 +59,9 @@ impl Device { subscriptions: 0 } } + pub fn delete_by_username(username1: String, conn: &mut SqliteConnection) -> Result { + use crate::schema::devices::dsl::*; + diesel::delete(devices.filter(username.eq(username1))).execute(conn) + } } \ No newline at end of file diff --git a/src/models/episode.rs b/src/models/episode.rs index 2edb6c88..1801d858 100644 --- a/src/models/episode.rs +++ b/src/models/episode.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::io::Error; use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; use diesel::{Queryable, QueryableByName, Insertable, SqliteConnection, RunQueryDsl, QueryDsl, BoolExpressionMethods, OptionalExtension, sql_query}; @@ -186,6 +187,14 @@ impl Episode{ } }).collect() } + + pub fn delete_by_username_and_episode(username1: String, conn: &mut SqliteConnection) ->Result<(),Error>{ + use crate::schema::episodes::username; + use crate::schema::episodes::dsl::episodes; + diesel::delete(episodes.filter(username.eq(username1))) + .execute(conn).expect(""); + Ok(()) + } } #[derive(Debug, Deserialize, Serialize)] diff --git a/src/models/favorites.rs b/src/models/favorites.rs index c4780aad..5fdc3fc9 100644 --- a/src/models/favorites.rs +++ b/src/models/favorites.rs @@ -11,4 +11,13 @@ pub struct Favorite{ pub username: String, pub podcast_id: i32, pub favored: bool +} + +impl Favorite{ + pub fn delete_by_username(username1: String, conn: &mut SqliteConnection) -> Result<(), + diesel::result::Error>{ + use crate::schema::favorites::dsl::*; + diesel::delete(favorites.filter(username.eq(username1))).execute(conn)?; + Ok(()) + } } \ No newline at end of file diff --git a/src/models/models.rs b/src/models/models.rs index e9bbbf4b..66f14336 100644 --- a/src/models/models.rs +++ b/src/models/models.rs @@ -56,6 +56,16 @@ pub struct PodcastHistoryItem { pub username: String } +impl PodcastHistoryItem{ + pub fn delete_by_username(username1: String, conn: &mut SqliteConnection) -> Result<(), + diesel::result::Error>{ + use crate::schema::podcast_history_items::dsl::*; + diesel::delete(podcast_history_items.filter(username.eq(username1))) + .execute(conn)?; + Ok(()) + } +} + #[derive(Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct PodcastWatchedEpisodeModel { diff --git a/src/models/session.rs b/src/models/session.rs index b5862e18..06d8abae 100644 --- a/src/models/session.rs +++ b/src/models/session.rs @@ -41,4 +41,11 @@ impl Session{ .filter(sessions::session_id.eq(session_id)) .get_result(conn) } + + pub fn delete_by_username(username1: &str, conn: &mut diesel::SqliteConnection) -> + Result{ + diesel::delete(sessions::table + .filter(sessions::username.eq(username1))) + .execute(conn) + } } \ No newline at end of file diff --git a/src/models/subscription.rs b/src/models/subscription.rs index 7530b8cd..5327573e 100644 --- a/src/models/subscription.rs +++ b/src/models/subscription.rs @@ -41,6 +41,13 @@ impl Subscription{ deleted: None } } + pub fn delete_by_username(username1: &str, conn: &mut SqliteConnection) -> + Result<(), Error>{ + use crate::schema::subscriptions::dsl::*; + diesel::delete(subscriptions.filter(username.eq(username1))) + .execute(conn).expect("Error deleting subscriptions of user"); + Ok(()) + } } diff --git a/src/models/user.rs b/src/models/user.rs index 2f8db441..1c73f8ea 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -2,7 +2,7 @@ use std::io::Error; use actix_web::HttpResponse; use chrono::NaiveDateTime; use diesel::prelude::{Insertable, Queryable}; -use diesel::{OptionalExtension, RunQueryDsl, SqliteConnection}; +use diesel::{OptionalExtension, RunQueryDsl, SqliteConnection, AsChangeset}; use diesel::associations::HasTable; use utoipa::ToSchema; use crate::schema::users; @@ -11,7 +11,8 @@ use diesel::ExpressionMethods; use dotenv::var; use crate::constants::constants::{BASIC_AUTH, OIDC_AUTH, Role, USERNAME}; -#[derive(Serialize, Deserialize, Queryable, Insertable, Clone, ToSchema, PartialEq, Debug)] +#[derive(Serialize, Deserialize, Queryable, Insertable, Clone, ToSchema, PartialEq, Debug, +AsChangeset)] #[serde(rename_all = "camelCase")] pub struct User { pub id: i32, @@ -189,4 +190,12 @@ impl User{ .expect("Error deleting user"); Ok(()) } + + pub fn update_user(user: User, conn: &mut SqliteConnection)->Result<(), Error>{ + use crate::schema::users::dsl::*; + diesel::update(users.filter(id.eq(user.clone().id))) + .set(user).execute(conn) + .expect("Error updating user"); + Ok(()) + } } \ No newline at end of file