summaryrefslogtreecommitdiff
path: root/src/server.rs
diff options
context:
space:
mode:
authorKjetil Orbekk <kjetil.orbekk@gmail.com>2017-07-13 07:28:42 -0400
committerKjetil Orbekk <kjetil.orbekk@gmail.com>2017-07-13 07:28:42 -0400
commitfe6d45474a2024fb362ee59f7a38f827283ac0c4 (patch)
treecc09092fac8bca86372939cabc61220b1e0e303c /src/server.rs
parentba1ab61901e657903a34b0b0acecb81c12b5e0d0 (diff)
add: Persistent user id.
This will be used to limit users to one vote per quote.
Diffstat (limited to 'src/server.rs')
-rw-r--r--src/server.rs58
1 files changed, 50 insertions, 8 deletions
diff --git a/src/server.rs b/src/server.rs
index 4816c33..54beb34 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -8,11 +8,14 @@ use rusqlite::Connection;
use std::collections::BTreeMap;
use persistent::Write;
use handlebars_iron::handlebars::to_json;
-use serde_json::Map;
+use serde_json;
use params;
use error::LinoError;
use chrono;
use logger::Logger;
+use iron_sessionstorage::{self, SessionStorage, SessionRequestExt};
+use iron_sessionstorage::backends::SignedCookieBackend;
+use rand::{OsRng, Rng};
#[derive(Debug)]
pub struct State {
@@ -22,6 +25,41 @@ impl iron::typemap::Key for State {
type Value = State;
}
+#[derive(Debug, Clone, Serialize)]
+struct UserId(u64);
+impl iron_sessionstorage::Value for UserId {
+ fn get_key() -> &'static str {
+ "user_id"
+ }
+ fn into_raw(self) -> String {
+ format!("{}", self.0)
+ }
+ fn from_raw(value: String) -> Option<Self> {
+ value.parse().ok().map(|i| UserId(i))
+ }
+}
+
+fn user_id(r: &mut Request) -> IronResult<UserId> {
+ if let Some(user_id) = r.session().get::<UserId>()? {
+ return Ok(user_id);
+ }
+
+ let mut rng = OsRng::new().map_err(|e| {
+ // This is ugly, but I don't know how to annotate the expression.
+ let e: LinoError = From::from(e);
+ e
+ })?;
+ let user_id = UserId(rng.next_u64());
+ r.session().set(user_id.clone())?;
+ Ok(user_id)
+}
+
+fn make_result(r: &mut Request) -> IronResult<serde_json::Map<String, serde_json::value::Value>> {
+ let mut result = serde_json::Map::new();
+ result.insert("user_id".to_string(), to_json(&user_id(r)?));
+ Ok(result)
+}
+
fn get_param(r: &mut Request, param: &str) -> IronResult<String> {
let map = itry!(r.get_ref::<params::Params>());
match map.get(param) {
@@ -67,7 +105,7 @@ fn make_renderer() -> HandlebarsEngine {
}
fn quotes(r: &mut Request) -> IronResult<Response> {
- let mut result = Map::new();
+ let mut result = make_result(r)?;
let quote_id = get_param(r, "id").ok().and_then(
|id| id.parse::<i64>().ok(),
);
@@ -90,9 +128,9 @@ fn quotes(r: &mut Request) -> IronResult<Response> {
)))
}
-fn add_get(_r: &mut Request) -> IronResult<Response> {
+fn add_get(r: &mut Request) -> IronResult<Response> {
let date = chrono::offset::Local::now().format("%Y-%m-%d").to_string();
- let mut result = Map::new();
+ let mut result = make_result(r)?;
result.insert("date".to_string(), to_json(&date));
Ok(Response::with((
status::Ok,
@@ -102,6 +140,7 @@ fn add_get(_r: &mut Request) -> IronResult<Response> {
}
fn add_post(r: &mut Request) -> IronResult<Response> {
+ let result = make_result(r)?;
let nick = get_param(r, "nick")?;
let date = get_param(r, "date")?;
let quote = get_param(r, "quote")?;
@@ -127,12 +166,12 @@ fn add_post(r: &mut Request) -> IronResult<Response> {
Ok(Response::with((
status::Ok,
Header(ContentType::html()),
- Template::new("add_post", Map::new()),
+ Template::new("add_post", result)
)))
}
fn approve(r: &mut Request) -> IronResult<Response> {
- let mut result = Map::new();
+ let mut result = make_result(r)?;
let quote_id = get_param(r, "id").ok().and_then(
|id| id.parse::<i64>().ok(),
);
@@ -185,7 +224,7 @@ pub fn vote(r: &mut Request) -> IronResult<Response> {
data::get_quote(&state.connection, quote_id)?
};
- let mut result = Map::new();
+ let mut result = make_result(r)?;
result.insert("quote".to_string(), to_json(&quote));
Ok(Response::with((
@@ -206,13 +245,16 @@ pub fn serve(state: State, port: u16) {
approve: get "/approve.jsp" => approve,
vote: get "/vote" => vote,
);
- let (logger_before, logger_after) = Logger::new(None);
let mut chain = Chain::new(router);
+ let (logger_before, logger_after) = Logger::new(None);
chain.link_before(logger_before);
+ let key = data::get_key(&state.connection, "session").expect("session key");
+ chain.link_around(SessionStorage::new(SignedCookieBackend::new(key)));
chain.link_after(make_renderer());
chain.link(Write::<State>::both(state));
chain.link_after(logger_after);
+
let bind_address = format!("{}:{}", "::", port);
let _server = Iron::new(chain).http(bind_address.as_str());
info!("Serving on {}", bind_address);