diff --git a/server-api/src/admin.rs b/server-api/src/admin.rs index 42a602c..1d39067 100644 --- a/server-api/src/admin.rs +++ b/server-api/src/admin.rs @@ -1,7 +1,7 @@ // Module deals endpoints pertaining to admin-only actions use hyper::{Response, Body}; -use hyper::StatusCode::{NOT_FOUND, BAD_REQUEST, INTERNAL_SERVER_ERROR}; +use hyper::StatusCode; use mysql_async::Pool; use mysql_async::error::Error as SqlError; @@ -10,37 +10,82 @@ use mysql_async::prelude::Queryable; use serde_json::Value; use crate::perms::ADMIN_PERMS; +use crate::db_types::UBigInt; -async fn modify_perms(p: &Pool, target: u64, new_perms: u64) -> Result<(), SqlError>{ - use mysql_async::params; +macro_rules! get_target_id { + ($obj:expr) => { + match $obj.get("target-id") { + Some(val) => val.as_u64(), + None => None + } + } +} + +async fn modify_perms(p: &Pool, uid: u64, new_perms: u64) -> Result<(), SqlError>{ + /* NOTE: this whole func will return Ok(UpdateStatus) + * */ + use mysql_async::{params, Conn}; let conn = p.get_conn().await?; + let (conn, prow):(Conn, Option<(UBigInt, UBigInt)>) = conn.first_exec( + "SELECT id, perms WHERE id = :id", + params!{"id" => uid} + ).await?; + + conn.prep_exec( "UPDATE members SET permissions = :perms WHERE id = :id", params!{ - "id" => target, + "id" => uid, "perms" => new_perms }).await?; Ok(()) } -async fn new_admin(p: &Pool, response: &mut Response, params: Value) { +pub async fn new_admin(p: &Pool, response: &mut Response, params: Value) { // @requires: owner level permission as regular admins can have conflict of interests - let target_id_opt: Option = match params.get("target-id") { - Some(val) => val.as_u64(), - None => None - }; - if let Some(uid) = target_id_opt { - if !modify_perms(p, uid, ADMIN_PERMS).await.is_ok() { - *response.status_mut() = NOT_FOUND; - *response.body_mut() = Body::from("User not found with that id"); - } + if let Some(uid) = get_target_id!(params) { + let _ = modify_perms(p, uid, ADMIN_PERMS).await; } else { // this is likely the users fault providing shit ass json - *response.status_mut() = BAD_REQUEST; + *response.status_mut() = StatusCode::BAD_REQUEST; *response.body_mut() = Body::from("Missing target user id"); } } +async fn update_member_permissions(p: &Pool, uid: u64, perms: u64) -> Result<(), SqlError>{ + use mysql_async::params; + let conn = p.get_conn().await?; + conn.prep_exec( + "UPDATE members permissions = :perms WHERE id = :id", + params!{ + "id" => uid, + "perms" => perms + } + ).await?; + + Ok(()) +} + +pub async fn set_permissions(p: &Pool, response: &mut Response, params: Value) { + // @requiresL: admin level permissions, admins can't touch other admins + let tuid = get_target_id!(params); + + let new_perms = match params.get("permissions") { + Some(val) => val.as_u64(), + None => None + }; + + match (tuid, new_perms) { + (Some(uid), Some(perms)) => { + if let Ok(_) = update_member_permissions(p, uid, perms).await { + } + }, + _ => { + *response.status_mut() = StatusCode::BAD_REQUEST; + *response.body_mut() = Body::from("Missing one or more parameters"); + } + } +} diff --git a/server-api/src/main.rs b/server-api/src/main.rs index cedcd1e..9cc0e45 100644 --- a/server-api/src/main.rs +++ b/server-api/src/main.rs @@ -57,6 +57,10 @@ async fn route_dispatcher(pool: &Pool, resp: &mut Response, meth: &Method, (POST, routes::CHANNELS_DELETE) => channels::delete_channel(pool, resp, params).await, /* MESSAGING */ (POST, routes::MESSAGE_SEND) => messages::send_message(pool, resp, params).await, + /* ADMIN */ + (POST, routes::SET_PERMS_BY_ADMIN) => admin::set_permissions(pool, resp, params).await, + /* OWNER */ + (POST, routes::SET_NEW_ADMIN) => admin::new_admin(pool, resp, params).await, _ => { // We attempt dynamic routes as fallback for a few reasons // 1. theres less of these than there are the static routes diff --git a/server-api/src/members.rs b/server-api/src/members.rs index 2e0c559..b2c75bb 100644 --- a/server-api/src/members.rs +++ b/server-api/src/members.rs @@ -16,6 +16,26 @@ pub struct Member { pub permissions: UBigInt, } +pub async fn get_member_row(p: &Pool, uid: u64) -> Result, Error> { + let conn = p.get_conn().await?; + type RowData = (VarChar, VarChar, BigInt, Integer, UBigInt); + let (_, db_row) : (Conn, Option) = conn.first_exec( + "SELECT secret, name, joindate, status, permissions FROM members WHERE id = :id", + params!{"id" => uid} + ).await?; + + if let Some(row) = db_row { + return Ok(Some(Member { + id: uid, + secret: row.0, + name: row.1, + joindate: row.2, + status: row.3, + permissions:4, + })) + } + return Ok(None) +} pub async fn insert_new_member(p: &Pool, name: VarChar, perms: u64) -> Result { use crate::auth::generate_secret; diff --git a/server-api/src/routes.rs b/server-api/src/routes.rs index 391bffb..8910feb 100644 --- a/server-api/src/routes.rs +++ b/server-api/src/routes.rs @@ -8,6 +8,10 @@ pub const MESSAGE_SEND: &'static str = "/message/send"; // requires @content pub const SERVER_META: &'static str = "/meta"; // open +// @requires: admin permissions +// +pub const SET_PERMS_BY_ADMIN: &'static str = "/admin/setpermisions"; +pub const SET_NEW_ADMIN: &'static str = "/owner/newadmin"; // @requiers: owner perms // potentially adding more bases later pub const DYNAMIC_ROUTE_BASES: [(&'static str, bool);3] = [ ("/join", true), // open