You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.9 KiB
176 lines
4.9 KiB
use crate::api::{ApiError, CurrentUser, JsonApi, PolicyError::*, Ugc}; |
|
use crate::cache::BlockDictCache; |
|
use crate::db_conn::Db; |
|
use crate::libs::diesel_logger::LoggingConnection; |
|
use crate::models::*; |
|
use crate::rds_conn::RdsConn; |
|
use crate::rds_models::*; |
|
use crate::schema; |
|
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; |
|
use rocket::form::Form; |
|
use rocket::futures::future; |
|
use rocket::futures::join; |
|
use rocket::serde::{json::json, Serialize}; |
|
use std::collections::HashMap; |
|
|
|
#[derive(FromForm)] |
|
pub struct CommentInput { |
|
#[field(validate = len(1..12289))] |
|
text: String, |
|
use_title: Option<i8>, |
|
} |
|
|
|
#[derive(Serialize)] |
|
#[serde(crate = "rocket::serde")] |
|
pub struct CommentOutput { |
|
cid: i32, |
|
text: String, |
|
author_title: String, |
|
can_del: bool, |
|
name_id: i32, |
|
is_tmp: bool, |
|
create_time: i64, |
|
is_blocked: bool, |
|
blocked_count: Option<i32>, |
|
// for old version frontend |
|
timestamp: i64, |
|
blocked: bool, |
|
} |
|
|
|
pub async fn c2output<'r>( |
|
p: &'r Post, |
|
cs: &[Comment], |
|
user: &CurrentUser, |
|
cached_block_dict: &HashMap<String, bool>, |
|
rconn: &RdsConn, |
|
) -> Vec<CommentOutput> { |
|
let mut hash2id = HashMap::<&String, i32>::from([(&p.author_hash, 0)]); |
|
let name_ids_iter = cs.iter().map(|c| match hash2id.get(&c.author_hash) { |
|
Some(id) => *id, |
|
None => { |
|
let x = hash2id.len().try_into().unwrap(); |
|
hash2id.insert(&c.author_hash, x); |
|
x |
|
} |
|
}); |
|
future::join_all(cs.iter().zip(name_ids_iter).map(|(c, name_id)| async move { |
|
if c.is_deleted { |
|
None |
|
} else { |
|
let is_blocked = cached_block_dict[&c.author_hash]; |
|
let can_view = user.is_admin |
|
|| (!is_blocked && user.id.is_some() || user.namehash.eq(&c.author_hash)); |
|
Some(CommentOutput { |
|
cid: c.id, |
|
text: (if can_view { &c.content } else { "" }).to_string(), |
|
author_title: c.author_title.to_string(), |
|
can_del: c.check_permission(user, "wd").is_ok(), |
|
name_id, |
|
is_tmp: c.is_tmp, |
|
create_time: c.create_time.timestamp(), |
|
is_blocked, |
|
blocked_count: if user.is_admin { |
|
BlockCounter::get_count(rconn, &c.author_hash) |
|
.await |
|
.ok() |
|
.flatten() |
|
} else { |
|
None |
|
}, |
|
timestamp: c.create_time.timestamp(), |
|
blocked: is_blocked, |
|
}) |
|
} |
|
})) |
|
.await |
|
.into_iter() |
|
.flatten() |
|
.collect() |
|
} |
|
|
|
#[get("/getcomment?<pid>")] |
|
pub async fn get_comment(pid: i32, user: CurrentUser, db: Db, rconn: RdsConn) -> JsonApi { |
|
let p = Post::get(&db, &rconn, pid).await?; |
|
if p.is_deleted { |
|
return Err(ApiError::Pc(IsDeleted)); |
|
} |
|
let cs = p.get_comments(&db, &rconn).await?; |
|
let hash_list = cs.iter().map(|c| &c.author_hash).collect::<Vec<_>>(); |
|
let cached_block_dict = BlockDictCache::init(&user.namehash, p.id, &rconn) |
|
.get_or_create(&user, &hash_list) |
|
.await?; |
|
let data = c2output(&p, &cs, &user, &cached_block_dict, &rconn).await; |
|
|
|
Ok(json!({ |
|
"code": 0, |
|
"data": data, |
|
"n_attentions": p.n_attentions, |
|
// for old version frontend |
|
"likenum": p.n_attentions, |
|
"attention": Attention::init(&user.namehash, &rconn).has(p.id).await? , |
|
})) |
|
} |
|
|
|
#[post("/docomment")] |
|
pub async fn old_add_comment() -> ApiError { |
|
OldApi.into() |
|
} |
|
|
|
#[post("/post/<pid>/comment", data = "<ci>")] |
|
pub async fn add_comment( |
|
pid: i32, |
|
ci: Form<CommentInput>, |
|
user: CurrentUser, |
|
db: Db, |
|
rconn: RdsConn, |
|
) -> JsonApi { |
|
let mut p = Post::get(&db, &rconn, pid).await?; |
|
let use_title = ci.use_title.is_some() || user.is_admin || user.is_candidate; |
|
let c = Comment::create( |
|
&db, |
|
NewComment { |
|
content: ci.text.to_string(), |
|
author_hash: user.namehash.to_string(), |
|
author_title: if use_title { |
|
user.custom_title |
|
} else { |
|
"".to_owned() |
|
}, |
|
is_tmp: user.id.is_none(), |
|
post_id: pid, |
|
}, |
|
) |
|
.await?; |
|
|
|
let mut att = Attention::init(&user.namehash, &rconn); |
|
let hs_delta; |
|
let at_delta; |
|
|
|
if !att.has(p.id).await? { |
|
hs_delta = 3; |
|
at_delta = 1; |
|
att.add(p.id).await?; |
|
} else { |
|
hs_delta = (p.n_comments < 3 * p.n_attentions) as i32; |
|
at_delta = 0; |
|
} |
|
|
|
update!( |
|
p, |
|
posts, |
|
&db, |
|
{ n_comments, add 1 }, |
|
{ last_comment_time, to c.create_time }, |
|
{ n_attentions, add at_delta }, |
|
{ hot_score, add hs_delta } |
|
); |
|
|
|
join!( |
|
p.refresh_cache(&rconn, false), |
|
p.clear_comments_cache(&rconn), |
|
); |
|
|
|
Ok(json!({ |
|
"code": 0 |
|
})) |
|
}
|
|
|