|  |  |  | @ -10,23 +10,19 @@ use jsonwebtoken::{EncodingKey, Header}; | 
		
	
		
			
				|  |  |  |  | use rocket::http::Status; | 
		
	
		
			
				|  |  |  |  | use rocket::request::Outcome; | 
		
	
		
			
				|  |  |  |  | use rocket::request::{FromRequest, Request}; | 
		
	
		
			
				|  |  |  |  | use rocket::serde::json::{json, Json, Value}; | 
		
	
		
			
				|  |  |  |  | use rocket::response; | 
		
	
		
			
				|  |  |  |  | use rocket::serde::json; | 
		
	
		
			
				|  |  |  |  | use rocket::serde::json::{json, Json}; | 
		
	
		
			
				|  |  |  |  | use rocket::State; | 
		
	
		
			
				|  |  |  |  | use serde::{Deserialize, Serialize}; | 
		
	
		
			
				|  |  |  |  | use serde::ser::{SerializeStruct, Serializer}; | 
		
	
		
			
				|  |  |  |  | use std::borrow::Cow; | 
		
	
		
			
				|  |  |  |  | use validator::ValidateArgs; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[derive(Debug, Responder)] | 
		
	
		
			
				|  |  |  |  | pub enum ApiResponseVariant { | 
		
	
		
			
				|  |  |  |  |     Status(Status), | 
		
	
		
			
				|  |  |  |  |     //    Redirect(Redirect),
 | 
		
	
		
			
				|  |  |  |  |     Value(Value), | 
		
	
		
			
				|  |  |  |  |     //    Flash(Flash<Redirect>)
 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | use std::fmt; | 
		
	
		
			
				|  |  |  |  | use validator::{ValidateArgs, ValidationErrors}; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[derive(Serialize, Deserialize, Debug)] | 
		
	
		
			
				|  |  |  |  | struct ApiResponse { | 
		
	
		
			
				|  |  |  |  |     result: Cow<'static, str>, | 
		
	
		
			
				|  |  |  |  |     ok: bool, | 
		
	
		
			
				|  |  |  |  |     #[serde(skip_serializing_if = "Option::is_none")] | 
		
	
		
			
				|  |  |  |  |     message: Option<Cow<'static, str>>, | 
		
	
		
			
				|  |  |  |  |     #[serde(skip_serializing_if = "Option::is_none")] | 
		
	
	
		
			
				
					
					|  |  |  | @ -34,26 +30,15 @@ struct ApiResponse { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl ApiResponse { | 
		
	
		
			
				|  |  |  |  |     const SUCCES_RESULT: Cow<'static, str> = Cow::Borrowed("Ok"); | 
		
	
		
			
				|  |  |  |  |     const FAILURE_RESULT: Cow<'static, str> = Cow::Borrowed("Failure"); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     const SUCCES: Self = Self { | 
		
	
		
			
				|  |  |  |  |         result: Self::SUCCES_RESULT, | 
		
	
		
			
				|  |  |  |  |         ok: true, | 
		
	
		
			
				|  |  |  |  |         message: None, | 
		
	
		
			
				|  |  |  |  |         jwt: None, | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     fn error(message: String) -> Self { | 
		
	
		
			
				|  |  |  |  |         Self { | 
		
	
		
			
				|  |  |  |  |             result: Self::FAILURE_RESULT, | 
		
	
		
			
				|  |  |  |  |             message: Some(Cow::Owned(message)), | 
		
	
		
			
				|  |  |  |  |             jwt: None, | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     fn login_response(jwt: String) -> Self { | 
		
	
		
			
				|  |  |  |  |         Self { | 
		
	
		
			
				|  |  |  |  |             result: Self::SUCCES_RESULT, | 
		
	
		
			
				|  |  |  |  |             ok: true, | 
		
	
		
			
				|  |  |  |  |             message: None, | 
		
	
		
			
				|  |  |  |  |             jwt: Some(Cow::Owned(jwt)), | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
	
		
			
				
					
					|  |  |  | @ -63,6 +48,59 @@ impl ApiResponse { | 
		
	
		
			
				|  |  |  |  | #[derive(Debug)] | 
		
	
		
			
				|  |  |  |  | pub enum ApiError { | 
		
	
		
			
				|  |  |  |  |     RequestError(String), | 
		
	
		
			
				|  |  |  |  |     ValidationErrors(ValidationErrors), | 
		
	
		
			
				|  |  |  |  |     Unauthorized, | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl fmt::Display for ApiError { | 
		
	
		
			
				|  |  |  |  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
		
	
		
			
				|  |  |  |  |         use ApiError::*; | 
		
	
		
			
				|  |  |  |  |         write!(f, "{}", match &self { | 
		
	
		
			
				|  |  |  |  |             RequestError(e) => e, | 
		
	
		
			
				|  |  |  |  |             ValidationErrors(_) => "???", | 
		
	
		
			
				|  |  |  |  |             Unauthorized => "username and password didn't match", | 
		
	
		
			
				|  |  |  |  |         }) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl From<schema::DatabaseError> for ApiError { | 
		
	
		
			
				|  |  |  |  |     fn from(e: schema::DatabaseError) -> Self { | 
		
	
		
			
				|  |  |  |  |         ApiError::RequestError(e.to_string()) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl From<ValidationErrors> for ApiError { | 
		
	
		
			
				|  |  |  |  |     fn from(e: ValidationErrors) -> Self { | 
		
	
		
			
				|  |  |  |  |         ApiError::ValidationErrors(e) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl Serialize for ApiError { | 
		
	
		
			
				|  |  |  |  |     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | 
		
	
		
			
				|  |  |  |  |     where | 
		
	
		
			
				|  |  |  |  |         S: Serializer, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |         let mut state = serializer.serialize_struct("ApiError", 2)?; | 
		
	
		
			
				|  |  |  |  |         state.serialize_field("ok", &false)?; | 
		
	
		
			
				|  |  |  |  |         state.serialize_field("message", &self.to_string())?; | 
		
	
		
			
				|  |  |  |  |         state.end() | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | impl<'r> response::Responder<'r, 'static> for ApiError { | 
		
	
		
			
				|  |  |  |  |     fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { | 
		
	
		
			
				|  |  |  |  |         use ApiError::*; | 
		
	
		
			
				|  |  |  |  |         let status = match self { | 
		
	
		
			
				|  |  |  |  |             RequestError(_) => Status::BadRequest, | 
		
	
		
			
				|  |  |  |  |             ValidationErrors(_) => Status::BadRequest, | 
		
	
		
			
				|  |  |  |  |             Unauthorized => Status::Unauthorized, | 
		
	
		
			
				|  |  |  |  |         }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         response::Response::build() | 
		
	
		
			
				|  |  |  |  |             .merge(json!(self).respond_to(req)?) | 
		
	
		
			
				|  |  |  |  |             .status(status) | 
		
	
		
			
				|  |  |  |  |             .ok() | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const AUTH_HEADER: &str = "Authorization"; | 
		
	
	
		
			
				
					
					|  |  |  | @ -104,14 +142,13 @@ impl<'r> FromRequest<'r> for schema::User { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[get("/gamenights")] | 
		
	
		
			
				|  |  |  |  | pub async fn gamenights(conn: DbConn, _user: schema::User) -> ApiResponseVariant { | 
		
	
		
			
				|  |  |  |  |     let gamenights = schema::get_all_gamenights(conn).await; | 
		
	
		
			
				|  |  |  |  |     ApiResponseVariant::Value(json!(gamenights)) | 
		
	
		
			
				|  |  |  |  | pub async fn gamenights(conn: DbConn, _user: schema::User) -> json::Value { | 
		
	
		
			
				|  |  |  |  |     json!(schema::get_all_gamenights(conn).await) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[get("/gamenights", rank = 2)] | 
		
	
		
			
				|  |  |  |  | pub async fn gamenights_unauthorized() -> ApiResponseVariant { | 
		
	
		
			
				|  |  |  |  |     ApiResponseVariant::Status(Status::Unauthorized) | 
		
	
		
			
				|  |  |  |  | pub async fn gamenights_unauthorized() -> Status { | 
		
	
		
			
				|  |  |  |  |     Status::Unauthorized | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[post("/gamenight", format = "application/json", data = "<gamenight_json>")] | 
		
	
	
		
			
				
					
					|  |  |  | @ -119,12 +156,12 @@ pub async fn gamenight_post_json( | 
		
	
		
			
				|  |  |  |  |     conn: DbConn, | 
		
	
		
			
				|  |  |  |  |     user: Option<schema::User>, | 
		
	
		
			
				|  |  |  |  |     gamenight_json: Json<schema::GameNightNoId>, | 
		
	
		
			
				|  |  |  |  | ) -> ApiResponseVariant { | 
		
	
		
			
				|  |  |  |  | ) -> Result<json::Value, Status> { | 
		
	
		
			
				|  |  |  |  |     if user.is_some() { | 
		
	
		
			
				|  |  |  |  |         schema::insert_gamenight(conn, gamenight_json.into_inner()).await; | 
		
	
		
			
				|  |  |  |  |         ApiResponseVariant::Value(json!(ApiResponse::SUCCES)) | 
		
	
		
			
				|  |  |  |  |         Ok(json!(ApiResponse::SUCCES)) | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |         ApiResponseVariant::Status(Status::Unauthorized) | 
		
	
		
			
				|  |  |  |  |         Err(Status::Unauthorized) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					
					|  |  |  | @ -132,23 +169,14 @@ pub async fn gamenight_post_json( | 
		
	
		
			
				|  |  |  |  | pub async fn register_post_json( | 
		
	
		
			
				|  |  |  |  |     conn: DbConn, | 
		
	
		
			
				|  |  |  |  |     register_json: Json<schema::Register>, | 
		
	
		
			
				|  |  |  |  | ) -> ApiResponseVariant { | 
		
	
		
			
				|  |  |  |  | ) -> Result<json::Value, ApiError> { | 
		
	
		
			
				|  |  |  |  |     let register = register_json.into_inner(); | 
		
	
		
			
				|  |  |  |  |     let register_clone = register.clone(); | 
		
	
		
			
				|  |  |  |  |     match conn | 
		
	
		
			
				|  |  |  |  |         .run(move |c| register_clone.validate_args((c, c))) | 
		
	
		
			
				|  |  |  |  |         .await | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |         Ok(()) => (), | 
		
	
		
			
				|  |  |  |  |         Err(error) => { | 
		
	
		
			
				|  |  |  |  |             return ApiResponseVariant::Value(json!(ApiResponse::error(error.to_string()))) | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     conn.run(move |c| register_clone.validate_args((c, c))) | 
		
	
		
			
				|  |  |  |  |         .await?; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     match schema::insert_user(conn, register).await { | 
		
	
		
			
				|  |  |  |  |         Ok(_) => ApiResponseVariant::Value(json!(ApiResponse::SUCCES)), | 
		
	
		
			
				|  |  |  |  |         Err(err) => ApiResponseVariant::Value(json!(ApiResponse::error(err.to_string()))), | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     schema::insert_user(conn, register).await?; | 
		
	
		
			
				|  |  |  |  |     Ok(json!(ApiResponse::SUCCES)) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #[derive(Debug, Serialize, Deserialize)] | 
		
	
	
		
			
				
					
					|  |  |  | @ -163,33 +191,25 @@ pub async fn login_post_json( | 
		
	
		
			
				|  |  |  |  |     conn: DbConn, | 
		
	
		
			
				|  |  |  |  |     config: &State<AppConfig>, | 
		
	
		
			
				|  |  |  |  |     login_json: Json<schema::Login>, | 
		
	
		
			
				|  |  |  |  | ) -> ApiResponseVariant { | 
		
	
		
			
				|  |  |  |  |     match schema::login(conn, login_json.into_inner()).await { | 
		
	
		
			
				|  |  |  |  |         Err(err) => ApiResponseVariant::Value(json!(ApiResponse::error(err.to_string()))), | 
		
	
		
			
				|  |  |  |  |         Ok(login_result) => { | 
		
	
		
			
				|  |  |  |  |             if !login_result.result { | 
		
	
		
			
				|  |  |  |  |                 return ApiResponseVariant::Value(json!(ApiResponse::error(String::from( | 
		
	
		
			
				|  |  |  |  |                     "username and password didn't match" | 
		
	
		
			
				|  |  |  |  |                 )))); | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  | ) -> Result<json::Value, ApiError> { | 
		
	
		
			
				|  |  |  |  |     let login_result = schema::login(conn, login_json.into_inner()).await?; | 
		
	
		
			
				|  |  |  |  |     if !login_result.result { | 
		
	
		
			
				|  |  |  |  |         return Err(ApiError::Unauthorized); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |             let my_claims = Claims { | 
		
	
		
			
				|  |  |  |  |                 exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), | 
		
	
		
			
				|  |  |  |  |                 uid: login_result.id.unwrap(), | 
		
	
		
			
				|  |  |  |  |                 role: login_result.role.unwrap(), | 
		
	
		
			
				|  |  |  |  |             }; | 
		
	
		
			
				|  |  |  |  |     let my_claims = Claims { | 
		
	
		
			
				|  |  |  |  |         exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), | 
		
	
		
			
				|  |  |  |  |         uid: login_result.id.unwrap(), | 
		
	
		
			
				|  |  |  |  |         role: login_result.role.unwrap(), | 
		
	
		
			
				|  |  |  |  |     }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |             let secret = &config.inner().jwt_secret; | 
		
	
		
			
				|  |  |  |  |             match encode( | 
		
	
		
			
				|  |  |  |  |                 &Header::default(), | 
		
	
		
			
				|  |  |  |  |                 &my_claims, | 
		
	
		
			
				|  |  |  |  |                 &EncodingKey::from_secret(secret.as_bytes()), | 
		
	
		
			
				|  |  |  |  |             ) { | 
		
	
		
			
				|  |  |  |  |                 Ok(token) => ApiResponseVariant::Value(json!(ApiResponse::login_response(token))), | 
		
	
		
			
				|  |  |  |  |                 Err(error) => { | 
		
	
		
			
				|  |  |  |  |                     ApiResponseVariant::Value(json!(ApiResponse::error(error.to_string()))) | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     let secret = &config.inner().jwt_secret; | 
		
	
		
			
				|  |  |  |  |     match encode( | 
		
	
		
			
				|  |  |  |  |         &Header::default(), | 
		
	
		
			
				|  |  |  |  |         &my_claims, | 
		
	
		
			
				|  |  |  |  |         &EncodingKey::from_secret(secret.as_bytes()), | 
		
	
		
			
				|  |  |  |  |     ) { | 
		
	
		
			
				|  |  |  |  |         Ok(token) => Ok(json!(ApiResponse::login_response(token))), | 
		
	
		
			
				|  |  |  |  |         Err(error) => Err(ApiError::RequestError(error.to_string())), | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					| 
							
							
							
						 |  |  | 
 |