join via invite seems to be scaffolded properly but now requires testing
This commit is contained in:
parent
2c6cdf9282
commit
157d133317
@ -1,4 +1,5 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use mysql_async;
|
use mysql_async;
|
||||||
use mysql_async::{Conn, Pool};
|
use mysql_async::{Conn, Pool};
|
||||||
@ -8,10 +9,11 @@ use mysql_async::prelude::{params, Queryable};
|
|||||||
use hyper::{Response, Body, StatusCode};
|
use hyper::{Response, Body, StatusCode};
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use rand::random;
|
|
||||||
|
|
||||||
use crate::db_types::{BigInt, Integer};
|
use crate::db_types::BigInt;
|
||||||
|
use crate::members::{self, Member};
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
struct Invite {
|
struct Invite {
|
||||||
id: BigInt,
|
id: BigInt,
|
||||||
uses: Option<BigInt>, // optional because some links are permanent
|
uses: Option<BigInt>, // optional because some links are permanent
|
||||||
@ -23,84 +25,77 @@ struct Invite {
|
|||||||
* are of the enum mysql_async::error::Error
|
* are of the enum mysql_async::error::Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
impl Invite {
|
async fn valid_invite(pool: &Pool, id: BigInt) -> Result<bool, Error>{
|
||||||
pub fn from_tuple(tup: (BigInt, Option<Integer>, bool)) -> Invite {
|
|
||||||
/*
|
|
||||||
* Let's us convert tuples from mysql into convenient invite structs */
|
|
||||||
Invite {
|
|
||||||
id: tup.0,
|
|
||||||
uses: tup.1,
|
|
||||||
expires: tup.2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_json_str(&self) -> String {
|
|
||||||
// TODO: Deprecate
|
|
||||||
let id = format!("\"id\":{}", self.id);
|
|
||||||
let expires = format!("\"expires\":{}", self.expires);
|
|
||||||
let uses = format!("\"uses\":{:?}", self.uses);
|
|
||||||
|
|
||||||
let mut data = String::from("{");
|
|
||||||
data.push_str(&format!("{},", id));
|
|
||||||
data.push_str(&format!("{},", expires));
|
|
||||||
data.push_str(&format!("{}}}", uses));
|
|
||||||
data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_invite_by_code(pool: &Pool, value: Option<&str>) -> Result<Option<Invite>, Error> {
|
|
||||||
if let Some(val) = value {
|
|
||||||
let conn = pool.get_conn().await?;
|
|
||||||
let db_row_result: (Conn, Option<(BigInt, Option<Integer>, bool)>) = conn
|
|
||||||
.first_exec(r"SELECT * FROM", mysql_async::params!{"code"=>val})
|
|
||||||
.await?;
|
|
||||||
if let Some(tup) = db_row_result.1 {
|
|
||||||
Ok(Some(Invite::from_tuple(tup)))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// basically nothing was found but nothing bad happened
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// again db didn't throw a fit but we don't have a good input
|
|
||||||
else {Ok(None)}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn record_invite_usage(pool: &Pool, data: &Invite) -> Result<(), Error>{
|
|
||||||
/*
|
/*
|
||||||
* By this this is called we really don't care about what happens as we've
|
* Fetches an invite from the database to check for validity
|
||||||
* already been querying the db and the likely hood of this seriously failing
|
*/
|
||||||
* is low enough to write a wall of text and not a wall of error handling code
|
|
||||||
*/
|
|
||||||
let conn = pool.get_conn().await?;
|
let conn = pool.get_conn().await?;
|
||||||
let _db_result = conn
|
let db_fetch_result: (Conn, Option<(Option<BigInt>, bool)>) =
|
||||||
.prep_exec(r"UPDATE invites SET uses = :uses WHERE id = :id", mysql_async::params!{
|
conn.first_exec("SELECT uses, expires FROM invites WHERE id = :id",
|
||||||
"uses" => data.uses - 1,
|
params!{"id" => id}).await?;
|
||||||
"id" => data.id
|
|
||||||
}).await?;
|
if let Some(row) = db_fetch_result.1 {
|
||||||
|
// if expires at all
|
||||||
|
if row.1 {
|
||||||
|
let now = Utc::now().timestamp();
|
||||||
|
// old?
|
||||||
|
let mut status = now > id;
|
||||||
|
// used?
|
||||||
|
if row.0.is_some() && status == false {
|
||||||
|
status = row.0.unwrap() <= 0; // safe unwrap since we know its Some(_)
|
||||||
|
}
|
||||||
|
return Ok(status)
|
||||||
|
}
|
||||||
|
// no expiry date? no problem
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
// prolly not a real id
|
||||||
|
else {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn route_join_invite_code(pool: &Pool, response: &mut Response<Body>, params: Value) -> Result<(), Error> {
|
async fn use_invite(pool: &Pool, code: Option<BigInt>) -> Option<Member>{
|
||||||
// collect some things first
|
/*
|
||||||
if let Some(code) = params.get("code") {
|
* Attempts to change the state of the current invite being provided
|
||||||
if let Some(row) = get_invite_by_code(pool, code.as_str()).await? {
|
*/
|
||||||
// since we have a row make sure the invite is valid
|
use crate::perms::GENERAL_NEW;
|
||||||
let now = Utc::now().timestamp() as u64;
|
let id = match code {
|
||||||
// usable and expires in the future
|
Some(id) => id,
|
||||||
if row.uses > 0 && row.expires > now {
|
None => 0
|
||||||
record_invite_usage(pool, &row).await?;
|
};
|
||||||
// TODO: assign some actual data to the body
|
|
||||||
*response.status_mut() = StatusCode::OK;
|
if let Ok(valid) = valid_invite(pool, id).await {
|
||||||
|
if valid {
|
||||||
|
match members::insert_new_member(pool, "Anonymous".into(), GENERAL_NEW).await {
|
||||||
|
Ok(member) => return Some(member),
|
||||||
|
Err(_) => return None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
*response.status_mut() = StatusCode::BAD_REQUEST;
|
return None;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
pub async fn join(pool: &Pool, response: &mut Response<Body>, params: Value) {
|
||||||
|
/*
|
||||||
|
* Main dispatcher for dealing with an attempted join via a given invide code
|
||||||
|
*/
|
||||||
|
let code = match params.get("invite-id") {
|
||||||
|
Some(val) => val.as_i64(),
|
||||||
|
None => None
|
||||||
|
};
|
||||||
|
|
||||||
|
match use_invite(&pool, code).await {
|
||||||
|
Some(new_account) => *response.body_mut() = Body::from(serde_json::to_string(&new_account).unwrap()),
|
||||||
|
None => {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn insert_new_invite(pool: &Pool, invite: &Invite) -> Result<(), Error>{
|
async fn insert_new_invite(pool: &Pool, invite: &Invite) -> Result<(), Error>{
|
||||||
@ -126,8 +121,9 @@ pub async fn create(pool: &Pool, response: &mut Response<Body>, params: Value) {
|
|||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: remove the unwrap
|
||||||
let expires = match params.get("expires") {
|
let expires = match params.get("expires") {
|
||||||
Some(val) => val.as_bool().unwrap(),
|
Some(val) => val.as_bool().unwrap_or(true),
|
||||||
None => true
|
None => true
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,6 +135,9 @@ pub async fn create(pool: &Pool, response: &mut Response<Body>, params: Value) {
|
|||||||
|
|
||||||
match insert_new_invite(&pool, &invite).await {
|
match insert_new_invite(&pool, &invite).await {
|
||||||
Ok(_) => *response.body_mut() = Body::from("yes"),
|
Ok(_) => *response.body_mut() = Body::from("yes"),
|
||||||
Err(mysqle) => *response.status_mut() = StatusCode::BAD_REQUEST
|
Err(mysqle) => {
|
||||||
|
println!("\tINVITES::CREATE::ERROR: {}", mysqle);
|
||||||
|
*response.status_mut() = StatusCode::BAD_REQUEST;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user