212 lines
7.3 KiB
Rust
212 lines
7.3 KiB
Rust
use mysql_async::{params, Pool, Conn};
|
|
use mysql_async::prelude::Queryable;
|
|
use mysql_async::error::Error as SqlError;
|
|
|
|
use async_trait::async_trait;
|
|
|
|
use serde::Serialize;
|
|
|
|
use crate::{Response, no_conn, sql_err};
|
|
use crate::{UBigInt, BigInt, Integer, VarChar};
|
|
|
|
use crate::common::{FromDB};
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct Member {
|
|
pub id: UBigInt,
|
|
pub secret: VarChar,
|
|
pub name: VarChar,
|
|
pub joindate: BigInt,
|
|
pub status: Integer,
|
|
pub permissions: UBigInt,
|
|
}
|
|
|
|
|
|
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;
|
|
/*
|
|
*
|
|
* conn = getconn
|
|
* result = conn.query
|
|
* return response based on result
|
|
*
|
|
*/
|
|
#[async_trait]
|
|
impl FromDB<Member, Integer> for Member {
|
|
type Row = Option<(VarChar, VarChar, BigInt, Integer, UBigInt)>;
|
|
|
|
async fn get(p: &Pool, id: UBigInt) -> Response<Self> {
|
|
if let Ok(conn) = p.get_conn().await {
|
|
let q = "SELECT secret, name, joindate, status, permissions FROM members WHERE id = :id";
|
|
let db_res : Result<(Conn, Self::Row), SqlError>
|
|
= conn.first_exec(q, params!{"id" => id}).await;
|
|
if let Ok((_, row)) = db_res {
|
|
return match row {
|
|
Some(row) => Response::Row(Self {
|
|
id: id,
|
|
secret: row.0,
|
|
name: row.1,
|
|
joindate: row.2,
|
|
status: row.3,
|
|
permissions: row.4
|
|
}),
|
|
None => Response::Empty
|
|
}
|
|
}
|
|
return Response::Other(sql_err!("Fetch failed"));
|
|
}
|
|
return Response::Other(no_conn!("Member::FromDB::get"));
|
|
}
|
|
|
|
async fn update(p: &Pool, row: Member) -> Response<Self> {
|
|
let q = r#"UPDATE members
|
|
SET status = :status, permissions = :perms, name = :name
|
|
WHERE id = :id"#;
|
|
|
|
if let Ok(conn) = p.get_conn().await {
|
|
let query = conn.drop_exec(q, params!{
|
|
"id" => row.id,
|
|
"status" => row.status,
|
|
"name" => row.name,
|
|
"perms" => row.permissions
|
|
}).await;
|
|
|
|
return match query {
|
|
Ok(_) => Response::Success,
|
|
Err(err) => Response::Other(sql_err!(err))
|
|
}
|
|
}
|
|
|
|
return Response::Other(no_conn!("db::Member::update"));
|
|
}
|
|
|
|
async fn delete(p: &Pool, id: UBigInt) -> Response<Self> {
|
|
if let Ok(conn) = p.get_conn().await {
|
|
let q = "DELETE from members WHERE id = :id";
|
|
let db_result: Result<Conn, SqlError>
|
|
= conn.drop_exec(q, params!{"id" => id}).await;
|
|
match Member::get(p, id).await {
|
|
Response::Row(_) => {
|
|
if let Ok(conn) = db_result {
|
|
return match conn.prep_exec("", params!{"id" => id}).await {
|
|
Ok(_) => Response::Success,
|
|
Err(_) => Response::Other(sql_err!("Member::FromDB::delete"))
|
|
}
|
|
}
|
|
return Response::Success
|
|
},
|
|
Response::Empty => return Response::Empty,
|
|
_ => return Response::Other(sql_err!("Member::FromDB::delete | another stupid get happened delid this"))
|
|
}
|
|
}
|
|
|
|
return Response::Empty;
|
|
}
|
|
|
|
async fn filter(p: &Pool, status: Integer) -> Response<Self> {
|
|
//! @params status
|
|
return match (p.get_conn().await, status) {
|
|
(Ok(conn), STATUS_ONLINE) | (Ok(conn), STATUS_OFFLINE) |
|
|
(Ok(conn), STATUS_AWAY) | (Ok(conn), STATUS_DO_NOT_DISTURB) => {
|
|
// TODO: Allow people to query somewhere in the middle of this set
|
|
// i.e. we should be able to get user 100 -> 150 instead of just the
|
|
// first 1000 people
|
|
let q =
|
|
"SELECT id, name, status, permissions FROM memebrs
|
|
WHERE status = :stat LIMIT 1000"; // high limit for now
|
|
if let Ok(query) = conn.prep_exec(q, params!{"stat" => status}).await {
|
|
let mapping_r = query.map_and_drop(|row| {
|
|
let (id, name, status, permissions): (UBigInt, VarChar, Integer, UBigInt) =
|
|
mysql_async::from_row(row);
|
|
|
|
Member {
|
|
id: id,
|
|
secret: "".into(), // no show for obv reasons
|
|
name: name,
|
|
joindate: 0, // doesn't matter
|
|
status: status,
|
|
permissions: permissions
|
|
}
|
|
}).await;
|
|
match mapping_r {
|
|
Ok((_, members)) => Response::Set(members),
|
|
Err(_) => Response::Other(sql_err!("db::Members::filter"))
|
|
}
|
|
}
|
|
else {
|
|
Response::Other(sql_err!("db::Members::filter"))
|
|
}
|
|
}
|
|
_ => Response::Other(sql_err!("err"))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Member {
|
|
pub async fn add(p: &Pool, name: &str, secret: &str, perms: u64) -> Result<Response<Self>, 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<Member>)
|
|
//! @returns : on_partial_succes => Ok(Response<Member>)
|
|
//! @returns : on_failure => Err(SomeBS)
|
|
use chrono::Utc;
|
|
|
|
let conn = p.get_conn().await?;
|
|
|
|
//name
|
|
//perms
|
|
//secret
|
|
let now: BigInt = Utc::now().timestamp();
|
|
|
|
|
|
let conn = conn.drop_exec(
|
|
"INSERT INTO members(secret, name, joindate, status, permissions)
|
|
VALUES(:secret, :name, :joindate, :status, :permissions)",
|
|
mysql_async::params!{
|
|
"secret" => secret.clone(),
|
|
"name" => name.clone(),
|
|
"joindate" => now,
|
|
"status" => STATUS_ONLINE,
|
|
"permissions" => perms
|
|
}).await?;
|
|
|
|
let (_, opt_id): (Conn, Option<UBigInt>) = conn.first_exec(
|
|
"SELECT id FROM members WHERE secret = :secret",
|
|
params!{
|
|
"secret" => secret.clone()
|
|
}).await?;
|
|
|
|
if let Some(id) = opt_id {
|
|
return Ok(Response::Row(Self {
|
|
id: id,
|
|
secret: secret.into(),
|
|
name: name.into(),
|
|
joindate: now,
|
|
status: STATUS_ONLINE,
|
|
permissions: perms
|
|
}))
|
|
}
|
|
|
|
return Ok(Response::Empty);
|
|
}
|
|
|
|
pub async fn update_perms(p: &Pool, uid: UBigInt, permissions: UBigInt) -> Result<UBigInt, SqlError> {
|
|
//! @return on_sucess Ok(NewPermisionsMask)
|
|
//!
|
|
let conn = p.get_conn().await?;
|
|
conn.drop_exec(
|
|
"UPDATE members SET permissions = :perms WHERE id = :id",
|
|
params!{
|
|
"id" => uid,
|
|
"perms" => permissions
|
|
}).await?;
|
|
|
|
Ok(permissions)
|
|
}
|
|
}
|