Browse Source

feat: set and user custom title

master
hole-thu 3 years ago
parent
commit
f5b0dbdbac
  1. 9
      src/api/comment.rs
  2. 2
      src/api/mod.rs
  3. 21
      src/api/operation.rs
  4. 14
      src/api/post.rs
  5. 2
      src/main.rs
  6. 26
      src/rds_models.rs

9
src/api/comment.rs

@ -16,7 +16,7 @@ use std::collections::HashMap;
#[derive(FromForm)]
pub struct CommentInput {
pid: i32,
#[field(validate = len(1..4097))]
#[field(validate = len(1..12289))]
text: String,
use_title: Option<i8>,
}
@ -118,7 +118,12 @@ pub async fn add_comment(
NewComment {
content: ci.text.to_string(),
author_hash: user.namehash.to_string(),
author_title: "".to_string(),
author_title: (if ci.use_title.is_some() {
CustomTitle::get(&rconn, &user.namehash).await?
} else {
None
})
.unwrap_or_default(),
is_tmp: user.id.is_none(),
post_id: ci.pid,
},

2
src/api/mod.rs

@ -84,6 +84,7 @@ pub enum PolicyError {
IsReported,
IsDeleted,
NotAllowed,
TitleUsed,
}
#[derive(Debug)]
@ -112,6 +113,7 @@ impl<'r> Responder<'r, 'static> for APIError {
PolicyError::IsReported => "内容被举报,处理中",
PolicyError::IsDeleted => "内容被删除",
PolicyError::NotAllowed => "不允许的操作",
PolicyError::TitleUsed => "头衔已被使用",
}
})
.respond_to(req),

21
src/api/operation.rs

@ -47,7 +47,7 @@ pub async fn delete(di: Form<DeleteInput>, user: CurrentUser, db: Db, rconn: Rds
(p.author_hash.clone(), p)
}
_ => { Err(NotAllowed) }?,
_ => Err(NotAllowed)?,
};
if user.is_admin && !user.namehash.eq(&author_hash) {
@ -128,11 +128,11 @@ pub async fn block(bi: Form<BlockInput>, user: CurrentUser, db: Db, rconn: RdsCo
let nh_to_block = match bi.content_type.as_str() {
"post" => Post::get(&db, &rconn, bi.id).await?.author_hash,
"comment" => Comment::get(&db, bi.id).await?.author_hash,
_ => { Err(NotAllowed) }?,
_ => Err(NotAllowed)?,
};
if nh_to_block.eq(&user.namehash) {
{ Err(NotAllowed) }?;
Err(NotAllowed)?;
}
blk.add(&nh_to_block).await?;
@ -150,3 +150,18 @@ pub async fn block(bi: Form<BlockInput>, user: CurrentUser, db: Db, rconn: RdsCo
},
}))
}
#[derive(FromForm)]
pub struct TitleInput {
#[field(validate = len(1..31))]
title: String,
}
#[post("/title", data = "<ti>")]
pub async fn set_title(ti: Form<TitleInput>, user: CurrentUser, rconn: RdsConn) -> JsonAPI {
if CustomTitle::set(&rconn, &user.namehash, &ti.title).await? {
code0!()
} else {
Err(TitleUsed)?
}
}

14
src/api/post.rs

@ -14,9 +14,9 @@ use rocket::serde::{json::json, Serialize};
#[derive(FromForm)]
pub struct PostInput {
#[field(validate = len(1..4097))]
#[field(validate = len(1..12289))]
text: String,
#[field(validate = len(0..33))]
#[field(validate = len(0..97))]
cw: String,
allow_search: Option<i8>,
use_title: Option<i8>,
@ -52,7 +52,7 @@ pub struct PostOutput {
#[derive(FromForm)]
pub struct CwInput {
pid: i32,
#[field(validate = len(0..33))]
#[field(validate = len(0..97))]
cw: String,
}
@ -145,6 +145,7 @@ pub async fn get_list(
Ok(json!({
"data": ps_data,
"count": ps_data.len(),
"custom_title": CustomTitle::get(&rconn, &user.namehash).await?,
"code": 0
}))
}
@ -162,7 +163,12 @@ pub async fn publish_post(
content: poi.text.to_string(),
cw: poi.cw.to_string(),
author_hash: user.namehash.to_string(),
author_title: "".to_string(),
author_title: (if poi.use_title.is_some() {
CustomTitle::get(&rconn, &user.namehash).await?
} else {
None
})
.unwrap_or_default(),
is_tmp: user.id.is_none(),
n_attentions: 1,
allow_search: poi.allow_search.is_some(),

2
src/main.rs

@ -66,6 +66,7 @@ async fn main() -> Result<(), rocket::Error> {
api::systemlog::get_systemlog,
api::operation::delete,
api::operation::report,
api::operation::set_title,
api::operation::block,
],
)
@ -96,4 +97,5 @@ fn init_database() {
async fn clear_outdate_redis_data(rconn: &RdsConn) {
rds_models::BannedUsers::clear(&rconn).await.unwrap();
rds_models::CustomTitle::clear(&rconn).await.unwrap();
}

26
src/rds_models.rs

@ -26,6 +26,7 @@ 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";
const KEY_DANGEROUS_USERS: &str = "hole_thu:dangerous_users"; //兼容一下旧版
const KEY_CUSTOM_TITLE: &str = "hole_v2:title";
const SYSTEMLOG_MAX_LEN: isize = 1000;
pub const BLOCK_THRESHOLD: i32 = 10;
@ -183,4 +184,29 @@ impl DangerousUser {
}
}
pub struct CustomTitle;
impl CustomTitle {
// return false if title exits
pub async fn set(rconn: &RdsConn, namehash: &str, title: &str) -> RedisResult<bool> {
let mut rconn = rconn.clone();
if rconn.hexists(KEY_CUSTOM_TITLE, title).await? {
Ok(false)
} else {
rconn.hset(KEY_CUSTOM_TITLE, namehash, title).await?;
rconn.hset(KEY_CUSTOM_TITLE, title, namehash).await?;
Ok(true)
}
}
pub async fn get(rconn: &RdsConn, namehash: &str) -> RedisResult<Option<String>> {
rconn.clone().hget(KEY_CUSTOM_TITLE, namehash).await
}
pub async fn clear(rconn: &RdsConn) -> RedisResult<()> {
rconn.clone().del(KEY_CUSTOM_TITLE).await
}
}
pub(crate) use init;

Loading…
Cancel
Save