diff --git a/docs/db_struct.sql b/docs/db_struct.sql index 4112730..4a4816f 100644 --- a/docs/db_struct.sql +++ b/docs/db_struct.sql @@ -302,5 +302,5 @@ CREATE TABLE `comunic_admin_log` ( `admin_id` INT NULL, `ip` VARCHAR(40) NULL, `time` INT NULL, - `action` VARCHAR(100) NULL, + `action` VARCHAR(255) NULL, PRIMARY KEY (`id`)); diff --git a/docs/migration.sql b/docs/migration.sql index db30ab4..faf46e3 100644 --- a/docs/migration.sql +++ b/docs/migration.sql @@ -28,5 +28,5 @@ CREATE TABLE `comunic_admin_log` ( `admin_id` INT NULL, `ip` VARCHAR(40) NULL, `time` INT NULL, - `action` VARCHAR(100) NULL, + `action` VARCHAR(255) NULL, PRIMARY KEY (`id`)); diff --git a/src/api_data/admin/admin_log_api.rs b/src/api_data/admin/admin_log_api.rs new file mode 100644 index 0000000..776fb99 --- /dev/null +++ b/src/api_data/admin/admin_log_api.rs @@ -0,0 +1,26 @@ +//! # Admin log api entry +//! +//! @author Pierre Hubert + +use crate::data::admin_action_log::{AdminActionLog, AdminAction}; + +#[derive(serde::Serialize)] +pub struct AdminLogAPI { + id: u64, + admin_id: u64, + ip: String, + time: u64, + action: AdminAction +} + +impl AdminLogAPI { + pub fn new(log: &AdminActionLog) -> Self{ + Self { + id: log.id, + admin_id: log.admin_id.id(), + ip: log.ip.to_string(), + time: log.time, + action: log.action.clone() + } + } +} \ No newline at end of file diff --git a/src/api_data/admin/mod.rs b/src/api_data/admin/mod.rs index 65b7801..d7a0e88 100644 --- a/src/api_data/admin/mod.rs +++ b/src/api_data/admin/mod.rs @@ -9,4 +9,5 @@ pub mod admin_info_api; pub mod admin_keys_api; pub mod admin_res_create_reset_token; pub mod admin_role_api; -pub mod admin_res_create_account; \ No newline at end of file +pub mod admin_res_create_account; +pub mod admin_log_api; \ No newline at end of file diff --git a/src/constants.rs b/src/constants.rs index 8815d29..b8b6209 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -273,7 +273,7 @@ pub mod admin { pub enum AdminRole { MANAGE_ADMINS, MANAGE_USERS, - ACCESS_FULL_ADMIN_LOGS, + ACCESS_ALL_ADMINS_LOGS, } pub struct AdminRoleMetadata { @@ -297,10 +297,10 @@ pub mod admin { description: "Allow the admin to list, reset password and delete Comunic users", }, AdminRoleMetadata { - role: AdminRole::ACCESS_FULL_ADMIN_LOGS, - id: "access_full_admin_logs", - name: "Access full admin logs", - description: "Allow the admin to access the action history of all admins", + role: AdminRole::ACCESS_ALL_ADMINS_LOGS, + id: "access_all_admins_logs", + name: "Access all admins logs", + description: "Allow the admin to access the action history (log) of all admins", } ]; } \ No newline at end of file diff --git a/src/controllers/admin/admin_logs_controller.rs b/src/controllers/admin/admin_logs_controller.rs new file mode 100644 index 0000000..4f6c992 --- /dev/null +++ b/src/controllers/admin/admin_logs_controller.rs @@ -0,0 +1,20 @@ +//! # Admin action history (logs) controller +//! +//! @author Pierre Hubert + +use crate::routes::RequestResult; +use crate::data::http_request_handler::HttpRequestHandler; +use crate::data::base_request_handler::BaseRequestHandler; +use crate::helpers::{admin_roles_helper, admin_log_helper}; +use crate::constants::admin::AdminRole; +use crate::api_data::admin::admin_log_api::AdminLogAPI; + +/// Get the list of logs of the user +pub fn get_list(r: &mut HttpRequestHandler) -> RequestResult { + let logs = match admin_roles_helper::has_role(r.admin_id()?, AdminRole::ACCESS_ALL_ADMINS_LOGS)? { + true => admin_log_helper::get_all_admin_logs(), + false => admin_log_helper::get_admin_logs(r.admin_id()?) + }?; + + r.set_response(logs.iter().map(AdminLogAPI::new).collect::>()) +} \ No newline at end of file diff --git a/src/controllers/admin/mod.rs b/src/controllers/admin/mod.rs index 34626d2..c755ee6 100644 --- a/src/controllers/admin/mod.rs +++ b/src/controllers/admin/mod.rs @@ -4,4 +4,5 @@ pub mod admin_account_controller; pub mod admin_keys_controller; -pub mod admin_roles_controller; \ No newline at end of file +pub mod admin_roles_controller; +pub mod admin_logs_controller; \ No newline at end of file diff --git a/src/data/admin_action_log.rs b/src/data/admin_action_log.rs index 34f2142..aec804c 100644 --- a/src/data/admin_action_log.rs +++ b/src/data/admin_action_log.rs @@ -2,7 +2,7 @@ use crate::data::admin::AdminID; -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, Clone)] pub enum AdminAction { AuthWithResetToken, AuthWithAccessKey { key: String, key_id: u64 }, diff --git a/src/helpers/admin_log_helper.rs b/src/helpers/admin_log_helper.rs index 54f1982..a1a600a 100644 --- a/src/helpers/admin_log_helper.rs +++ b/src/helpers/admin_log_helper.rs @@ -5,7 +5,7 @@ use crate::constants::conservation_policy::ADMIN_ACTIONS_LOG_LIFETIME; use crate::constants::database_tables_names::ADMIN_LOGS_TABLE; use crate::data::admin::AdminID; -use crate::data::admin_action_log::AdminAction; +use crate::data::admin_action_log::{AdminAction, AdminActionLog}; use crate::data::error::Res; use crate::helpers::database; use crate::utils::date_utils::time; @@ -26,4 +26,28 @@ pub fn clean_old_logs() -> Res { .set_custom_where("time < ?") .add_custom_where_arg_u64(time() - ADMIN_ACTIONS_LOG_LIFETIME.as_secs()) .exec() +} + + +/// Get all administrators action log history +pub fn get_all_admin_logs() -> Res> { + database::QueryInfo::new(ADMIN_LOGS_TABLE).exec(db_to_log) +} + +/// Get a specific administrator action log history +pub fn get_admin_logs(id: AdminID) -> Res> { + database::QueryInfo::new(ADMIN_LOGS_TABLE) + .cond_admin_id("admin_id", id) + .exec(db_to_log) +} + +fn db_to_log(row: &database::RowResult) -> Res { + Ok(AdminActionLog { + id: row.get_u64("id")?, + admin_id: row.get_admin_id("admin_id")?, + ip: row.get_str("ip")?, + time: row.get_u64("time")?, + action: serde_json::from_str(&row.get_str("action")?) + .unwrap_or(AdminAction::UnsupportedAction), + }) } \ No newline at end of file diff --git a/src/routes.rs b/src/routes.rs index bd1267e..c507c04 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -391,5 +391,8 @@ pub fn get_routes() -> Vec { // Admin roles controller Route::admin_post("/admin/roles/list", Box::new(admin_roles_controller::get_list)), Route::admin_post_restricted("/admin/roles/toggle", Box::new(admin_roles_controller::toggle), AdminRole::MANAGE_ADMINS), + + // Admin logs controller + Route::admin_post("/admin/logs/list", Box::new(admin_logs_controller::get_list)), ] } \ No newline at end of file