Added add_authenticated_input_route

This commit is contained in:
Emi Tatsuo 2020-11-22 20:56:15 -05:00
parent edbfd3ed78
commit 9916770bd2
Signed by: Emi
GPG key ID: 68FAB2E2E6DFC98B
2 changed files with 71 additions and 21 deletions

View file

@ -30,7 +30,7 @@ async fn main() -> Result<()> {
// Add our main routes // Add our main routes
.add_authenticated_route("/", handle_main) .add_authenticated_route("/", handle_main)
.add_authenticated_route("/update", handle_update) .add_authenticated_input_route("/update", "Enter your new string:", handle_update)
// Add routes for handling user authentication // Add routes for handling user authentication
.add_um_routes::<String>("/") .add_um_routes::<String>("/")
@ -64,14 +64,13 @@ async fn handle_main(_req: Request, user: RegisteredUser<String>) -> Result<Resp
/// The update endpoint /// The update endpoint
/// ///
/// Users can update their secret string here. /// Users can update their secret string here.
async fn handle_update(request: Request, mut user: RegisteredUser<String>) -> Result<Response> { async fn handle_update(_request: Request, mut user: RegisteredUser<String>, input: String) -> Result<Response> {
// If the user is logged in, check to see if they provided any input. If they // The user has already been prompted to log in if they weren't and asked to give an
// have, we can set that input as their new string, otherwise we ask them for it // input string, so all we need to do is...
if let Some(string) = request.input() {
// Update the users data // Update the users data
*user.as_mut() = string.to_owned(); *user.as_mut() = input;
// Render a response // Render a response
let response = Document::new() let response = Document::new()
@ -81,11 +80,4 @@ async fn handle_update(request: Request, mut user: RegisteredUser<String>) -> Re
.into(); .into();
Ok(response) Ok(response)
} else {
// Ask the user for some input
Ok(Response::input_lossy("Enter your new string"))
}
} }

View file

@ -47,6 +47,38 @@ pub trait UserManagementRoutes: private::Sealed {
UserData: Serialize + DeserializeOwned + 'static + Send + Sync, UserData: Serialize + DeserializeOwned + 'static + Send + Sync,
Handler: Clone + Send + Sync + 'static + Fn(Request, RegisteredUser<UserData>) -> F, Handler: Clone + Send + Sync + 'static + Fn(Request, RegisteredUser<UserData>) -> F,
F: Send + Sync + 'static + Future<Output = Result<Response>>; F: Send + Sync + 'static + Future<Output = Result<Response>>;
/// Add a special route that requires users to be logged in AND takes input
///
/// Like with [`add_authenticated_route()`](Self::add_authenticated_route()), this
/// prompts the user to log in if they haven't already, but additionally prompts the
/// user for input before running the handler with both the user object and the input
/// they provided.
///
/// To a user, this might look something like this:
/// * Click a link to `/your/route`
/// * See a screen asking you to sign in or create an account
/// * Create a new account, and return to the app.
/// * Now, clicking the link shows the prompt provided.
/// * After entering some value, the user receives the response from the handler.
///
/// For a user whose already logged in, this will just look like a normal input route,
/// where they enter some query and see a page. This method just takes the burden of
/// having to check if the user sent a query string and respond with an INPUT response
/// if not.
///
/// To use this method, ensure that [`add_um_routes()`](Self::add_um_routes()) has
/// also been called.
fn add_authenticated_input_route<UserData, Handler, F>(
self,
path: &'static str,
prompt: &'static str,
handler: Handler,
) -> Self
where
UserData: Serialize + DeserializeOwned + 'static + Send + Sync,
Handler: Clone + Send + Sync + 'static + Fn(Request, RegisteredUser<UserData>, String) -> F,
F: Send + Sync + 'static + Future<Output = Result<Response>>;
} }
impl<A: ToSocketAddrs> UserManagementRoutes for crate::Builder<A> { impl<A: ToSocketAddrs> UserManagementRoutes for crate::Builder<A> {
@ -91,6 +123,32 @@ impl<A: ToSocketAddrs> UserManagementRoutes for crate::Builder<A> {
} }
}) })
} }
/// Add a special route that requires users to be logged in AND takes input
///
/// See [`UserManagementRoutes::add_authenticated_input_route()`]
fn add_authenticated_input_route<UserData, Handler, F>(
self,
path: &'static str,
prompt: &'static str,
handler: Handler,
) -> Self
where
UserData: Serialize + DeserializeOwned + 'static + Send + Sync,
Handler: Clone + Send + Sync + 'static + Fn(Request, RegisteredUser<UserData>, String) -> F,
F: Send + Sync + 'static + Future<Output = Result<Response>>
{
self.add_authenticated_route(path, move|request, user| {
let handler = handler.clone();
async move {
if let Some(input) = request.input().map(str::to_owned) {
(handler.clone())(request, user, input).await
} else {
Response::input(prompt)
}
}
})
}
} }
async fn handle_base<UserData: Serialize + DeserializeOwned>(request: Request, redirect: &'static str) -> Result<Response> { async fn handle_base<UserData: Serialize + DeserializeOwned>(request: Request, redirect: &'static str) -> Result<Response> {