summaryrefslogtreecommitdiff
path: root/src/data.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/data.rs')
-rw-r--r--src/data.rs114
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)
"#,
- &[&quote_id, &score],
+ &[&quote_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),
))