1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-29 16:56:28 +00:00
comunicapiv3/src/main.rs

241 lines
6.8 KiB
Rust

use comunic_server::{cleanup_thread, server};
use comunic_server::constants::admin::{ADMIN_ROLES_LIST, AdminRole};
use comunic_server::data::admin::NewAdmin;
use comunic_server::data::config::{conf, Config};
use comunic_server::data::error::Res;
use comunic_server::data::user::UserID;
use comunic_server::helpers::{account_helper, admin_account_helper, admin_roles_helper, database};
use comunic_server::utils::date_utils::current_year;
type MainActionFunction = Res;
struct Action {
name: &'static str,
description: &'static str,
arguments: Vec<&'static str>,
function: Box<dyn Fn(Vec<String>) -> MainActionFunction>,
}
fn get_actions() -> Vec<Action> {
vec![
// Start server
Action {
name: "serve",
description: "Start the Comunic Server (default action)",
arguments: vec![],
function: Box::new(serve),
},
// Show help
Action {
name: "help",
description: "Show this help",
arguments: vec![],
function: Box::new(help),
},
// Reset password
Action {
name: "reset_password",
description: "Create a password reset URL for a user",
arguments: vec!["user_id"],
function: Box::new(reset_password),
},
// Create a new administrator
Action {
name: "create_admin",
description: "Create a new administrator account",
arguments: vec!["name", "email"],
function: Box::new(create_admin),
},
// Create a reset token for an admin
Action {
name: "create_admin_reset_token",
description: "Create a new reset token to register a new access key to an admin account",
arguments: vec!["email"],
function: Box::new(create_admin_reset_token),
},
// Get the list of available admin roles
Action {
name: "list_admin_roles",
description: "Get the list of available admin roles",
arguments: vec![],
function: Box::new(list_admin_roles),
},
// Attribute a role to an admin
Action {
name: "grant_admin_role",
description: "Grant a role to an admin",
arguments: vec!["mail", "role_id"],
function: Box::new(grant_admin_role),
}
]
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
let args: Vec<String> = std::env::args().collect();
let conf_file = match args.get(1) {
Some(el) => el.to_string(),
None => {
eprintln!("Please specify configuration file as first argument!");
std::process::exit(-3);
}
};
// Load configuration
Config::load(&conf_file).expect("Could not load configuration!");
// Connect to the database
database::connect(&conf().database).expect("Could not connect to database!");
// Get selected action
let action = args
.get(2)
.map(|a| a.as_str())
.unwrap_or("serve")
.to_string();
let actions = get_actions();
let selected_action = actions
.iter()
.filter(|p| p.name.eq(&action))
.next();
let selected_action = match selected_action {
None => {
eprintln!("Action {} invalid! For more information try 'help'!", action);
std::process::exit(-1);
}
Some(a) => a
};
if !selected_action.arguments.is_empty() && selected_action.arguments.len() + 3 != args.len() {
eprintln!("Invalid number of arguments!");
std::process::exit(-2);
}
let args = match args.len() {
0 | 1 | 2 => vec![],
_ => (&args[3..]).to_vec()
};
let res = (selected_action.function)(args.to_vec());
res.expect("Failed to execute action!");
Ok(())
}
/// Start Comunic Server (main action)
fn serve(_a: Vec<String>) -> Res {
let t = std::thread::spawn(|| {
let sys = actix::System::new("sys");
let promise = async {
// Start cleanup thread
cleanup_thread::start().expect("Failed to start cleanup thread!");
// Start the server
server::start_server(conf()).await
};
tokio::runtime::Runtime::new().unwrap().block_on(promise)
.expect("Failed to start server!");
let _ = sys.run();
});
t.join().unwrap();
Ok(())
}
fn help(_a: Vec<String>) -> Res {
println!("Comunic API v3 Server - (c) Pierre HUBERT 2012 - {}", current_year());
println!("Usage: {} [conf-file] [action] [args...]", std::env::args().next().unwrap());
println!("Available actions:");
for action in get_actions() {
println!("\t{} {}\t- {}",
action.name,
action.arguments.iter().map(|s| format!("[{}]", s)).collect::<Vec<String>>().join(" "),
action.description
);
}
Ok(())
}
fn reset_password(args: Vec<String>) -> Res {
let user_id = UserID::new(args[0].parse::<u64>()?);
let token = account_helper::generate_password_reset_token(&user_id)?;
println!("{}", conf().password_reset_url.replace("{TOKEN}", &token));
Ok(())
}
fn create_admin(args: Vec<String>) -> Res {
let new_admin = NewAdmin {
name: args[0].to_string(),
email: args[1].to_string(),
};
if !mailchecker::is_valid(&new_admin.email) {
eprintln!("Specified email address is not valid!");
std::process::exit(-1);
}
let id = admin_account_helper::create(&new_admin)
.expect("Failed to create account!");
println!("* New admin ID: {}", id.id());
Ok(())
}
fn create_admin_reset_token(args: Vec<String>) -> Res {
let admin = admin_account_helper::find_admin_by_email(&args[0])
.expect("Failed to load admin information!");
println!("Generate a new reset token for {} ({})", admin.name, admin.email);
let token = admin_account_helper::create_new_reset_token(admin.id)
.expect("Failed to create admin reset token!");
println!("Reset token: {}", token.token);
Ok(())
}
fn list_admin_roles(_a: Vec<String>) -> Res {
println!("Here are the currently defined roles in the code:\n");
for role in Vec::from(ADMIN_ROLES_LIST) {
println!("* {} - {}\n{}\n", role.id, role.name, role.description);
}
Ok(())
}
fn grant_admin_role(args: Vec<String>) -> Res {
let role = AdminRole::from_id(&args[1])
.expect("Requested role does not exist!");
let admin = admin_account_helper::find_admin_by_email(&args[0])
.expect("Failed to load admin information!");
if admin.roles.contains(&role) {
eprintln!("The administrator has already this role!");
std::process::exit(-3);
}
admin_roles_helper::add_role(admin.id, role)?;
println!("Success.");
Ok(())
}