use mysql_async::{params, Pool}; use mysql_async::prelude::Queryable; use mysql_async::Error as SqlError; use crate::{UBigInt, Integer, VarChar}; use crate::{PublicMember, Member, Response}; use rand::RngCore; pub const STATUS_ONLINE: Integer = 0; pub const STATUS_OFFLINE: Integer = 1; pub const STATUS_AWAY: Integer = 2; pub const STATUS_DO_NOT_DISTURB: Integer = 3; impl Member { pub async fn get(p: &Pool, id: UBigInt) -> Result, SqlError> { //! @returns Row on success //! @returns Other on failure let mut conn = p.get_conn().await?; let q = "SELECT secret, name, status, permissions FROM members WHERE id = :id"; let params = params!{"id" => id}; let row: Option<(VarChar, VarChar, Integer, UBigInt)> = conn.exec_first(q, params).await?; if let Some((secret, name, status, permissions)) = row { Ok(Response::Row(Member { id, secret, name, status, permissions })) } else { Ok(Response::Empty) } } pub async fn filter(p: &Pool, status: Integer) -> Result, SqlError> { //! @params status i32 //! @returns Response::Set(PublicMember) if !(status == STATUS_ONLINE || status == STATUS_AWAY || status == STATUS_OFFLINE || status == STATUS_DO_NOT_DISTURB) { Ok(Response::RestrictedInput(format!("Invalid status"))) } else { let mut conn = p.get_conn().await?; let q = "SELECT id, name, status, permissions FROM members WHERE status = :stat LIMIT 100"; // high limit for now let params = params!{"stat" => status}; let members = conn.exec_map(q, params, |(id, name , status, permissions)| { PublicMember { id, name, status, permissions } }).await?; Ok(Response::Set(members)) } } pub async fn add(p: &Pool, name: &str, enc_secret: &str, perms: u64) -> Result, SqlError> { //! @param {pool} p //! @param {&str} name of new user //! @param {&str} encrypted secret : userland auth module should have a function for this //! @param {u64} permissions mask //! @returns : on_succes => Ok(Response) //! @returns : on_partial_succes => Ok(Response) //! @returns : on_failure => Err(SomeBS) let mut conn = p.get_conn().await?; let id: u64 = rand::rngs::OsRng.next_u64(); conn.exec_drop( "INSERT INTO members(id, secret, name, status, permissions) VALUES(:id, :secret, :name, :status, :permissions)", mysql_async::params!{ "id" => id, "secret" => enc_secret.clone(), "name" => name.clone(), "status" => STATUS_ONLINE, "permissions" => perms }).await?; return Ok(Response::Row(Self { id, secret: enc_secret.into(), name: name.into(), status: STATUS_ONLINE, permissions: perms })) } pub async fn update_perms(p: &Pool, uid: UBigInt, permissions: UBigInt) -> Result { //! @return on_sucess Ok(NewPermisionsMask) //! @throws Err(SqlError) let mut conn = p.get_conn().await?; conn.exec_drop( "UPDATE members SET permissions = :perms WHERE id = :id", params!{ "id" => uid, "perms" => permissions }).await?; Ok(permissions) } pub async fn update_nick(p: &Pool, uid: UBigInt, new_nick: &str) -> Result<(), SqlError> { let mut conn = p.get_conn().await?; conn.exec_drop( "UPDATE members SET name = :nick WHERE id = id", params!{ "id" => uid, "nick" => new_nick }).await?; Ok(()) } } impl PublicMember { pub async fn get_online(p: &Pool, status: Integer) -> Result, SqlError> { let valid_status = status == STATUS_ONLINE || status == STATUS_AWAY || status == STATUS_OFFLINE || status == STATUS_DO_NOT_DISTURB; if !valid_status { return Ok(Response::RestrictedInput(format!("Invalid status value"))); } else { let mut conn = p.get_conn().await?; let q = "SELECT id, name, permissions FROM members WHERE status = :status LIMIT 1000"; let params = params!{"status" => status}; let members = conn.exec_map(q, params, |(id, name, permissions)| { PublicMember { id, name, permissions, status } }).await?; return Ok(Response::Set(members)); } } }