diff options
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/request.rs | 65 |
2 files changed, 64 insertions, 3 deletions
@@ -1,6 +1,6 @@ [package] name = "sputnik" -version = "0.3.3" +version = "0.3.4" authors = ["Martin Fischer <martin@push-f.com>"] license = "MIT" description = "A lightweight layer on top of hyper to facilitate building web applications." diff --git a/src/request.rs b/src/request.rs index f2392b8..195e601 100644 --- a/src/request.rs +++ b/src/request.rs @@ -9,7 +9,7 @@ use std::{collections::HashMap, sync::Arc}; use rand::{Rng, distributions::Alphanumeric}; use async_trait::async_trait; -use crate::response::SputnikHeaders; +use crate::response::{SputnikHeaders, delete_cookie}; const CSRF_COOKIE_NAME : &str = "csrf"; @@ -88,6 +88,67 @@ impl std::fmt::Display for CsrfToken { } } +const FLASH_COOKIE_NAME: &str = "flash"; + +/// Show the user a message after redirecting them. +pub struct Flash { + name: String, + message: String, +} + +impl From<Flash> for Cookie<'_> { + fn from(flash: Flash) -> Self { + Cookie::build(FLASH_COOKIE_NAME, format!("{}:{}", flash.name, flash.message)) + .max_age(Duration::minutes(5)).finish() + } +} + +impl Flash { + /// If the request has a flash cookie retrieve it and append a set-cookie + /// header to delete the cookie to [`SputnikParts::response_headers`]. + pub fn from_request(req: &mut Parts) -> Option<Self> { + req.cookies().get(FLASH_COOKIE_NAME) + .and_then(|cookie| { + req.response_headers().set_cookie(delete_cookie(FLASH_COOKIE_NAME)); + let mut iter = cookie.value().splitn(2, ':'); + if let (Some(name), Some(message)) = (iter.next(), iter.next()) { + return Some(Flash{name: name.to_owned(), message: message.to_owned()}) + } + None + }) + } + + /// Constructs a new Flash message. The name must not contain a colon (`:`). + pub fn new(name: String, message: String) -> Self { + Flash{name, message} + } + + /// Constructs a new "success" Flash message. + pub fn success(message: String) -> Self { + Flash{name: "success".to_owned(), message} + } + + /// Constructs a new "warning" Flash message. + pub fn warning(message: String) -> Self { + Flash{name: "warning".to_owned(), message} + } + + /// Constructs a new "error" Flash message. + pub fn error(message: String) -> Self { + Flash{name: "error".to_owned(), message} + } + + /// Returns the name of the Flash message. + pub fn name(&self) -> &str { + &self.name + } + + /// Returns the message of the Flash message. + pub fn message(&self) -> &str { + &self.message + } +} + impl CsrfToken { /// Returns a CSRF token, either extracted from the `csrf` cookie or newly /// generated if the cookie wasn't sent (in which case a set-cookie header is @@ -96,7 +157,7 @@ impl CsrfToken { /// If there is no cookie, calling this method multiple times only generates /// a new token on the first call, further calls return the previously /// generated token. - pub fn from_request(req: &mut Parts) -> CsrfToken { + pub fn from_request(req: &mut Parts) -> Self { if let Some(token) = req.extensions.get::<CsrfToken>() { return token.clone() } |