feat: poll
This commit is contained in:
@@ -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 = Post::get_multi(&db, &rconn, &ids).await?;
|
||||||
let ps_data = ps2outputs(&ps, &user, &db, &rconn).await;
|
let ps_data = ps2outputs(&ps, &user, &db, &rconn).await;
|
||||||
|
|
||||||
Ok(json!({
|
code0!(ps_data)
|
||||||
"code": 0,
|
|
||||||
"data": ps_data,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ macro_rules! code0 {
|
|||||||
() => (
|
() => (
|
||||||
Ok(json!({"code": 0}))
|
Ok(json!({"code": 0}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
($data:expr) => (
|
||||||
|
Ok(json!({
|
||||||
|
"code": 0,
|
||||||
|
"data": $data,
|
||||||
|
}))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[catch(401)]
|
#[catch(401)]
|
||||||
@@ -228,3 +235,4 @@ pub mod operation;
|
|||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod systemlog;
|
pub mod systemlog;
|
||||||
|
pub mod vote;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::api::comment::{c2output, CommentOutput};
|
use crate::api::comment::{c2output, CommentOutput};
|
||||||
|
use crate::api::vote::get_poll_dict;
|
||||||
use crate::api::{CurrentUser, JsonAPI, UGC};
|
use crate::api::{CurrentUser, JsonAPI, UGC};
|
||||||
use crate::db_conn::Db;
|
use crate::db_conn::Db;
|
||||||
use crate::libs::diesel_logger::LoggingConnection;
|
use crate::libs::diesel_logger::LoggingConnection;
|
||||||
@@ -10,7 +11,10 @@ use chrono::{offset::Utc, DateTime};
|
|||||||
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
|
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||||
use rocket::form::Form;
|
use rocket::form::Form;
|
||||||
use rocket::futures::future;
|
use rocket::futures::future;
|
||||||
use rocket::serde::{json::json, Serialize};
|
use rocket::serde::{
|
||||||
|
json::{json, Value},
|
||||||
|
Serialize,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(FromForm)]
|
#[derive(FromForm)]
|
||||||
pub struct PostInput {
|
pub struct PostInput {
|
||||||
@@ -20,6 +24,8 @@ pub struct PostInput {
|
|||||||
cw: String,
|
cw: String,
|
||||||
allow_search: Option<i8>,
|
allow_search: Option<i8>,
|
||||||
use_title: Option<i8>,
|
use_title: Option<i8>,
|
||||||
|
#[field(validate = len(0..97))]
|
||||||
|
poll_options: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -42,6 +48,7 @@ pub struct PostOutput {
|
|||||||
hot_score: Option<i32>,
|
hot_score: Option<i32>,
|
||||||
is_blocked: bool,
|
is_blocked: bool,
|
||||||
blocked_count: Option<i32>,
|
blocked_count: Option<i32>,
|
||||||
|
poll: Option<Value>,
|
||||||
// for old version frontend
|
// for old version frontend
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
likenum: i32,
|
likenum: i32,
|
||||||
@@ -98,6 +105,7 @@ async fn p2output(p: &Post, user: &CurrentUser, db: &Db, rconn: &RdsConn) -> Pos
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
poll: get_poll_dict(p.id, rconn, &user.namehash).await,
|
||||||
// for old version frontend
|
// for old version frontend
|
||||||
timestamp: p.create_time.timestamp(),
|
timestamp: p.create_time.timestamp(),
|
||||||
likenum: p.n_attentions,
|
likenum: p.n_attentions,
|
||||||
@@ -177,6 +185,12 @@ pub async fn publish_post(
|
|||||||
.await?;
|
.await?;
|
||||||
Attention::init(&user.namehash, &rconn).add(p.id).await?;
|
Attention::init(&user.namehash, &rconn).add(p.id).await?;
|
||||||
p.refresh_cache(&rconn, true).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!()
|
code0!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ async fn main() -> Result<(), rocket::Error> {
|
|||||||
api::operation::report,
|
api::operation::report,
|
||||||
api::operation::set_title,
|
api::operation::set_title,
|
||||||
api::operation::block,
|
api::operation::block,
|
||||||
|
api::vote::vote,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.register(
|
.register(
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ use rocket::serde::json::serde_json;
|
|||||||
use rocket::serde::{Deserialize, Serialize};
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
macro_rules! init {
|
macro_rules! init {
|
||||||
|
() => {
|
||||||
|
pub fn init(rconn: &RdsConn) -> Self {
|
||||||
|
Self {
|
||||||
|
rconn: rconn.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
($ktype:ty, $formatter:expr) => {
|
($ktype:ty, $formatter:expr) => {
|
||||||
pub fn init(k: $ktype, rconn: &RdsConn) -> Self {
|
pub fn init(k: $ktype, rconn: &RdsConn) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -13,15 +20,32 @@ macro_rules! init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
() => {
|
($k1type:ty, $k2type:ty, $formatter:expr) => {
|
||||||
pub fn init(rconn: &RdsConn) -> Self {
|
pub fn init(k1: $k1type, k2: $k2type, rconn: &RdsConn) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
key: format!($formatter, k1, k2),
|
||||||
rconn: rconn.clone(),
|
rconn: rconn.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! has {
|
||||||
|
($vtype:ty) => {
|
||||||
|
pub async fn has(&mut self, v: $vtype) -> RedisResult<bool> {
|
||||||
|
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_SYSTEMLOG: &str = "hole_v2:systemlog_list";
|
||||||
const KEY_BANNED_USERS: &str = "hole_v2:banned_user_hash_list";
|
const KEY_BANNED_USERS: &str = "hole_v2:banned_user_hash_list";
|
||||||
const KEY_BLOCKED_COUNTER: &str = "hole_v2:blocked_counter";
|
const KEY_BLOCKED_COUNTER: &str = "hole_v2:blocked_counter";
|
||||||
@@ -39,18 +63,14 @@ pub struct Attention {
|
|||||||
impl Attention {
|
impl Attention {
|
||||||
init!(&str, "hole_v2:attention:{}");
|
init!(&str, "hole_v2:attention:{}");
|
||||||
|
|
||||||
pub async fn add(&mut self, pid: i32) -> RedisResult<()> {
|
add!(i32);
|
||||||
self.rconn.sadd(&self.key, pid).await
|
|
||||||
}
|
has!(i32);
|
||||||
|
|
||||||
pub async fn remove(&mut self, pid: i32) -> RedisResult<()> {
|
pub async fn remove(&mut self, pid: i32) -> RedisResult<()> {
|
||||||
self.rconn.srem(&self.key, pid).await
|
self.rconn.srem(&self.key, pid).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn has(&mut self, pid: i32) -> RedisResult<bool> {
|
|
||||||
self.rconn.sismember(&self.key, pid).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn all(&mut self) -> RedisResult<Vec<i32>> {
|
pub async fn all(&mut self) -> RedisResult<Vec<i32>> {
|
||||||
self.rconn.smembers(&self.key).await
|
self.rconn.smembers(&self.key).await
|
||||||
}
|
}
|
||||||
@@ -135,13 +155,9 @@ pub struct BlockedUsers {
|
|||||||
impl BlockedUsers {
|
impl BlockedUsers {
|
||||||
init!(i32, "hole_v2:blocked_users:{}");
|
init!(i32, "hole_v2:blocked_users:{}");
|
||||||
|
|
||||||
pub async fn add(&mut self, namehash: &str) -> RedisResult<()> {
|
add!(&str);
|
||||||
self.rconn.sadd(&self.key, namehash).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn has(&mut self, namehash: &str) -> RedisResult<bool> {
|
has!(&str);
|
||||||
self.rconn.sismember(&self.key, namehash).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn check_blocked(
|
pub async fn check_blocked(
|
||||||
rconn: &RdsConn,
|
rconn: &RdsConn,
|
||||||
@@ -153,7 +169,7 @@ impl BlockedUsers {
|
|||||||
Some(id) => Self::init(id, rconn).has(author_hash).await?,
|
Some(id) => Self::init(id, rconn).has(author_hash).await?,
|
||||||
None => false,
|
None => false,
|
||||||
} || (DangerousUser::has(rconn, author_hash).await?
|
} || (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<()> {
|
pub async fn clear(rconn: &RdsConn) -> RedisResult<()> {
|
||||||
rconn.clone().del(KEY_CUSTOM_TITLE).await
|
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<String>) -> RedisResult<()> {
|
||||||
|
self.rconn.del(&self.key).await?;
|
||||||
|
self.rconn.rpush(&self.key, v).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_list(&mut self) -> RedisResult<Vec<String>> {
|
||||||
|
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<usize> {
|
||||||
|
self.rconn.scard(&self.key).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use init;
|
pub(crate) use init;
|
||||||
|
|||||||
Reference in New Issue
Block a user