// Module handles creating invites for potentially new users use diesel::{self, prelude::*}; use rocket_contrib::json::Json; use rand::random; use crate::DBConn; use crate::models::Invite; use crate::schema; use crate::users::new_user_response; use crate::payload; use chrono::{Duration, Utc}; /* TODO: both the generation and usage endpoints for invites need the following * meaningful responses * authentication */ #[get("/generate")] pub fn generate_invite(conn: DBConn) -> Json { let dt = Utc::now() + Duration::minutes(30); // TODO:[maybe] ensure no collisions by doing a quick database check here let mut new_invite = Invite { id: random::(), // hopefully there won't ever be collision with this size of pool uses: 1, // default/hardcorded for now expires: dt.timestamp() as u64 }; // Next we cache this invite let result = diesel::insert_into(schema::invites::table) .values(&new_invite) .execute(&conn.0); // Finally we attempt to return _something_ match result { Ok(_val) => { Json(new_invite) } Err(_e) => { new_invite.id = 0; new_invite.expires = 0; new_invite.uses = 0; Json(new_invite) } } } #[get("/")] pub fn use_invite(hash: u64, conn: DBConn) -> Json { // Grab the token from our table to make sure it's even there to begin with use schema::invites::dsl::*; use schema::users::dsl::*; let diesel_result: Result = invites.filter(id.eq(hash)).first(&conn.0); // TODO: this is getting moved elsewhere to clean up so ignore this for now if let Ok(data) = diesel_result { match data.uses { 1 ... std::i32::MAX => { let user = crate::users::create_new_user(); match diesel::insert_into(users).values(&user).execute(&conn.0) { Ok(_v) => Json(new_user_response(&Some(user), None)), // an issue on our end gets a 500 response Err(_e) => Json(new_user_response(&None, Some("Unable to create user"))) } } // The invite has been used up and thus should be removed std::i32::MIN ... 0 => { // bruh let _ = diesel::delete(invites.filter(id.eq(data.id))) .execute(&conn.0) .expect("Could not delete invite"); Json(new_user_response(&None, Some("Invalid invite"))) } } } else { Json(new_user_response(&None, Some("Could not create user"))) } } #[cfg(test)] mod invite_tests { use super::*; use rocket; use rocket::local::Client; use rocket::http::Status; use serde_json; #[test] fn request_invite() { let rocket = rocket::ignite() .mount("/invite", routes![generate_invite]) .attach(DBConn::fairing()); let client = Client::new(rocket).expect("Invalid rocket instance"); let mut response = client.get("/invite/generate").dispatch(); assert_eq!(response.status(), Status::Ok); match response.body_string() { Some(val) => { let invite: Result = serde_json::from_str(&val); match invite { Ok(val) => { println!("{:#?}", val) } Err(e) => { panic!("{}", e) } } } None => { println!("bro wtf"); } } } #[test] fn use_invite() { let app = rocket::ignite() .mount("/invite", routes![generate_invite, use_invite]) .attach(DBConn::fairing()); // We assume in this test that invite generation is fine let client = Client::new(app).expect("Invalid rocket instance"); let mut r = client.get("/invite/generate").dispatch(); let invite: Invite = serde_json::from_str(&r.body_string().unwrap()).unwrap(); // TODO: for some reason we can't use a regular struct so figure that out at some point let mut response = client.get(format!("/invite/{}", invite.id)).dispatch(); let body: String = response.body_string().unwrap(); println!("{}", body); } }