diff options
Diffstat (limited to 'src/data.rs')
-rw-r--r-- | src/data.rs | 114 |
1 files changed, 79 insertions, 35 deletions
diff --git a/src/data.rs b/src/data.rs index a5d7afb..8178bb9 100644 --- a/src/data.rs +++ b/src/data.rs @@ -3,6 +3,12 @@ use error::{Result, LinoError}; use rand::{OsRng, Rng}; #[derive(Serialize, Debug, Clone)] +pub struct Vote { + value: i32, + is_user_vote: bool, +} + +#[derive(Serialize, Debug, Clone)] pub struct Quote { id: i64, date: String, @@ -11,6 +17,46 @@ pub struct Quote { points: i32, votes: i32, content: String, + vote_options: Vec<Vote>, +} + +fn make_quote( + id: i64, + date: String, + author: String, + content: String, + user_vote: Option<i32>, + points: i32, + votes: i32, +) -> Quote { + fn make_vote_options(user_vote: Option<i32>) -> Vec<Vote> { + (1..6) + .map({ + |v| { + Vote { + value: v, + is_user_vote: Some(v) == user_vote, + } + } + }) + .collect() + } + + let score = if votes > 0 { + format!("{:.1}", points as f64 / votes as f64) + } else { + "—".to_string() + }; + Quote { + id: id, + date: date, + author: author, + points: points, + votes: votes, + content: content, + score: score, + vote_options: make_vote_options(user_vote), + } } pub fn init(c: &Connection) -> Result<()> { @@ -28,9 +74,11 @@ pub fn init(c: &Connection) -> Result<()> { CREATE TABLE IF NOT EXISTS votes ( id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, quote_id INTEGER NOT NULL, score INTEGER NOT NULL, FOREIGN KEY(quote_id) REFERENCES quotes(id) + CONSTRAINT unique_vote UNIQUE (user_id, quote_id) ); CREATE TABLE IF NOT EXISTS keys ( @@ -65,12 +113,12 @@ pub fn populate_test_db(c: &Connection) -> Result<()> { (2, 1, '2017-07-09', 'orbekk', 'test quote2'), (3, 0, '2017-07-09', 'orbekk', 'test quote3'); - INSERT INTO votes (quote_id, score) VALUES - (1, 2), - (1, 3), - (1, 1), - (2, 1), - (2, 2); + INSERT INTO votes (quote_id, user_id, score) VALUES + (1, 1, 2), + (1, 2, 3), + (1, 3, 1), + (2, 1, 1), + (2, 4, 2); "#, )); Ok(()) @@ -99,13 +147,13 @@ pub fn new_quote(c: &Connection, date: &str, author: &str, content: &str) -> Res Ok(()) } -pub fn new_vote(c: &Connection, quote_id: i64, score: i32) -> Result<()> { +pub fn new_vote(c: &Connection, user_id: i64, quote_id: i64, score: i32) -> Result<()> { c.execute( r#" - INSERT INTO votes (quote_id, score) VALUES - (?1, ?2) + INSERT OR REPLACE INTO votes (quote_id, user_id, score) VALUES + (?1, ?2, ?3) "#, - &["e_id, &score], + &["e_id, &user_id, &score], )?; info!("New vote: quote_id({}) score({})", quote_id, score); Ok(()) @@ -137,6 +185,7 @@ pub fn delete_quote(c: &Connection, quote_id: i64) -> Result<()> { fn internal_get_quotes( c: &Connection, id: Option<i64>, + user_id: i64, ordering: &str, approved: bool, ) -> Result<Vec<Quote>> { @@ -144,37 +193,32 @@ fn internal_get_quotes( // ?1: bool, whether to query for a specific quote // ?2: i64, quote id to use if ?1 is true // ?3: bool, whether to fetch approved or not approved quotes + // ?4: i64, user_id let mut stmt = c.prepare( r#" - SELECT q.id, q.quote_date, q.author, q.content, + SELECT q.id, q.quote_date, q.author, q.content, uv.score, COALESCE(sum(v.score), 0), count(v.score) FROM quotes q LEFT JOIN votes v ON (q.id = v.quote_id) - WHERE (?1 AND q.id = ?2) OR (NOT ?1 AND q.approved = ?3) - GROUP BY 1, 2, 3, 4; + LEFT JOIN votes uv ON (q.id = uv.quote_id AND uv.user_id = ?4) + WHERE ((?1 AND q.id = ?2) OR (NOT ?1 AND q.approved = ?3)) + GROUP BY 1, 2, 3, 4, 5; ORDER BY q.id DESC; "#, )?; let rows = stmt.query_map( - &[&id.is_some(), &id.unwrap_or(-1), &approved], + &[&id.is_some(), &id.unwrap_or(-1), &approved, &user_id], |row| { - let points = row.get(4); - let votes = row.get(5); - let score = if votes > 0 { - format!("{:.1}", points as f64 / votes as f64) - } else { - "—".to_string() - }; - Quote { - id: row.get(0), - date: row.get(1), - author: row.get(2), - content: row.get(3), - score: score, - points: points, - votes: votes, - } + make_quote( + row.get(0), + row.get(1), + row.get(2), + row.get(3), + row.get(4), + row.get(5), + row.get(6), + ) }, )?; @@ -195,16 +239,16 @@ fn internal_get_quotes( }) } -pub fn get_quotes(c: &Connection, ordering: &str) -> Result<Vec<Quote>> { - internal_get_quotes(c, None, ordering, true) +pub fn get_quotes(c: &Connection, user_id: i64, ordering: &str) -> Result<Vec<Quote>> { + internal_get_quotes(c, None, user_id, ordering, true) } pub fn get_pending_quotes(c: &Connection) -> Result<Vec<Quote>> { - internal_get_quotes(c, None, "", false) + internal_get_quotes(c, None, 0, "", false) } -pub fn get_quote(c: &Connection, id: i64) -> Result<Quote> { - let quotes = internal_get_quotes(c, Some(id), "", true)?; +pub fn get_quote(c: &Connection, id: i64, user_id: i64) -> Result<Quote> { + let quotes = internal_get_quotes(c, Some(id), user_id, "", true)?; quotes.into_iter().next().ok_or(LinoError::NotFound( format!("quote with id {}", id), )) |