diff --git a/src/api/attention.rs b/src/api/attention.rs index 60bbfbe..caf9fca 100644 --- a/src/api/attention.rs +++ b/src/api/attention.rs @@ -68,8 +68,5 @@ pub async fn get_attention(user: CurrentUser, db: Db, rconn: RdsConn) -> JsonAPI let ps = Post::get_multi(&db, &rconn, &ids).await?; let ps_data = ps2outputs(&ps, &user, &db, &rconn).await; - Ok(json!({ - "code": 0, - "data": ps_data, - })) + code0!(ps_data) } diff --git a/src/api/mod.rs b/src/api/mod.rs index 94db3a7..81a1bcf 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -16,6 +16,13 @@ macro_rules! code0 { () => ( Ok(json!({"code": 0})) ); + + ($data:expr) => ( + Ok(json!({ + "code": 0, + "data": $data, + })) + ); } #[catch(401)] @@ -228,3 +235,4 @@ pub mod operation; pub mod post; pub mod search; pub mod systemlog; +pub mod vote; diff --git a/src/api/post.rs b/src/api/post.rs index a3f35d4..6252a25 100644 --- a/src/api/post.rs +++ b/src/api/post.rs @@ -1,4 +1,5 @@ use crate::api::comment::{c2output, CommentOutput}; +use crate::api::vote::get_poll_dict; use crate::api::{CurrentUser, JsonAPI, UGC}; use crate::db_conn::Db; use crate::libs::diesel_logger::LoggingConnection; @@ -10,7 +11,10 @@ use chrono::{offset::Utc, DateTime}; use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; use rocket::form::Form; use rocket::futures::future; -use rocket::serde::{json::json, Serialize}; +use rocket::serde::{ + json::{json, Value}, + Serialize, +}; #[derive(FromForm)] pub struct PostInput { @@ -20,6 +24,8 @@ pub struct PostInput { cw: String, allow_search: Option, use_title: Option, + #[field(validate = len(0..97))] + poll_options: Vec, } #[derive(Serialize)] @@ -42,6 +48,7 @@ pub struct PostOutput { hot_score: Option, is_blocked: bool, blocked_count: Option, + poll: Option, // for old version frontend timestamp: i64, likenum: i32, @@ -98,6 +105,7 @@ async fn p2output(p: &Post, user: &CurrentUser, db: &Db, rconn: &RdsConn) -> Pos } else { None }, + poll: get_poll_dict(p.id, rconn, &user.namehash).await, // for old version frontend timestamp: p.create_time.timestamp(), likenum: p.n_attentions, @@ -177,6 +185,12 @@ pub async fn publish_post( .await?; Attention::init(&user.namehash, &rconn).add(p.id).await?; p.refresh_cache(&rconn, true).await; + + if !poi.poll_options.is_empty() { + PollOption::init(p.id, &rconn) + .set_list(&poi.poll_options) + .await?; + } code0!() } diff --git a/src/main.rs b/src/main.rs index dac0d70..93e7481 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,7 @@ async fn main() -> Result<(), rocket::Error> { api::operation::report, api::operation::set_title, api::operation::block, + api::vote::vote, ], ) .register( diff --git a/src/rds_models.rs b/src/rds_models.rs index 8f958be..6fd1cbf 100644 --- a/src/rds_models.rs +++ b/src/rds_models.rs @@ -5,6 +5,13 @@ use rocket::serde::json::serde_json; use rocket::serde::{Deserialize, Serialize}; macro_rules! init { + () => { + pub fn init(rconn: &RdsConn) -> Self { + Self { + rconn: rconn.clone(), + } + } + }; ($ktype:ty, $formatter:expr) => { pub fn init(k: $ktype, rconn: &RdsConn) -> Self { Self { @@ -13,15 +20,32 @@ macro_rules! init { } } }; - () => { - pub fn init(rconn: &RdsConn) -> Self { + ($k1type:ty, $k2type:ty, $formatter:expr) => { + pub fn init(k1: $k1type, k2: $k2type, rconn: &RdsConn) -> Self { Self { + key: format!($formatter, k1, k2), rconn: rconn.clone(), } } }; } +macro_rules! has { + ($vtype:ty) => { + pub async fn has(&mut self, v: $vtype) -> RedisResult { + self.rconn.sismember(&self.key, v).await + } + }; +} + +macro_rules! add { + ($vtype:ty) => { + pub async fn add(&mut self, v: $vtype) -> RedisResult<()> { + self.rconn.sadd(&self.key, v).await + } + }; +} + const KEY_SYSTEMLOG: &str = "hole_v2:systemlog_list"; const KEY_BANNED_USERS: &str = "hole_v2:banned_user_hash_list"; const KEY_BLOCKED_COUNTER: &str = "hole_v2:blocked_counter"; @@ -39,18 +63,14 @@ pub struct Attention { impl Attention { init!(&str, "hole_v2:attention:{}"); - pub async fn add(&mut self, pid: i32) -> RedisResult<()> { - self.rconn.sadd(&self.key, pid).await - } + add!(i32); + + has!(i32); pub async fn remove(&mut self, pid: i32) -> RedisResult<()> { self.rconn.srem(&self.key, pid).await } - pub async fn has(&mut self, pid: i32) -> RedisResult { - self.rconn.sismember(&self.key, pid).await - } - pub async fn all(&mut self) -> RedisResult> { self.rconn.smembers(&self.key).await } @@ -135,13 +155,9 @@ pub struct BlockedUsers { impl BlockedUsers { init!(i32, "hole_v2:blocked_users:{}"); - pub async fn add(&mut self, namehash: &str) -> RedisResult<()> { - self.rconn.sadd(&self.key, namehash).await - } + add!(&str); - pub async fn has(&mut self, namehash: &str) -> RedisResult { - self.rconn.sismember(&self.key, namehash).await - } + has!(&str); pub async fn check_blocked( rconn: &RdsConn, @@ -153,7 +169,7 @@ impl BlockedUsers { Some(id) => Self::init(id, rconn).has(author_hash).await?, None => false, } || (DangerousUser::has(rconn, author_hash).await? - && !DangerousUser::has(rconn,viewer_hash).await?)) + && !DangerousUser::has(rconn, viewer_hash).await?)) } } @@ -206,7 +222,41 @@ impl CustomTitle { pub async fn clear(rconn: &RdsConn) -> RedisResult<()> { rconn.clone().del(KEY_CUSTOM_TITLE).await } +} +pub struct PollOption { + key: String, + rconn: RdsConn, +} + +impl PollOption { + init!(i32, "hole_thu:poll_opts:{}"); + + pub async fn set_list(&mut self, v: &Vec) -> RedisResult<()> { + self.rconn.del(&self.key).await?; + self.rconn.rpush(&self.key, v).await + } + + pub async fn get_list(&mut self) -> RedisResult> { + self.rconn.lrange(&self.key, 0, -1).await + } +} + +pub struct PollVote { + key: String, + rconn: RdsConn, +} + +impl PollVote { + init!(i32, usize, "hole_thu:poll_votes:{}:{}"); + + add!(&str); + + has!(&str); + + pub async fn count(&mut self) -> RedisResult { + self.rconn.scard(&self.key).await + } } pub(crate) use init;