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)] #[derive(FromForm)]
pub struct CommentInput { pub struct CommentInput {
pid: i32, pid: i32,
#[field(validate = len(1..4097))] #[field(validate = len(1..12289))]
text: String, text: String,
use_title: Option<i8>, use_title: Option<i8>,
} }
@ -118,7 +118,12 @@ pub async fn add_comment(
NewComment { NewComment {
content: ci.text.to_string(), content: ci.text.to_string(),
author_hash: user.namehash.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(), is_tmp: user.id.is_none(),
post_id: ci.pid, post_id: ci.pid,
}, },

2
src/api/mod.rs

@ -84,6 +84,7 @@ pub enum PolicyError {
IsReported, IsReported,
IsDeleted, IsDeleted,
NotAllowed, NotAllowed,
TitleUsed,
} }
#[derive(Debug)] #[derive(Debug)]
@ -112,6 +113,7 @@ impl<'r> Responder<'r, 'static> for APIError {
PolicyError::IsReported => "内容被举报,处理中", PolicyError::IsReported => "内容被举报,处理中",
PolicyError::IsDeleted => "内容被删除", PolicyError::IsDeleted => "内容被删除",
PolicyError::NotAllowed => "不允许的操作", PolicyError::NotAllowed => "不允许的操作",
PolicyError::TitleUsed => "头衔已被使用",
} }
}) })
.respond_to(req), .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) (p.author_hash.clone(), p)
} }
_ => { Err(NotAllowed) }?, _ => Err(NotAllowed)?,
}; };
if user.is_admin && !user.namehash.eq(&author_hash) { 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() { let nh_to_block = match bi.content_type.as_str() {
"post" => Post::get(&db, &rconn, bi.id).await?.author_hash, "post" => Post::get(&db, &rconn, bi.id).await?.author_hash,
"comment" => Comment::get(&db, 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) { if nh_to_block.eq(&user.namehash) {
{ Err(NotAllowed) }?; Err(NotAllowed)?;
} }
blk.add(&nh_to_block).await?; 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)] #[derive(FromForm)]
pub struct PostInput { pub struct PostInput {
#[field(validate = len(1..4097))] #[field(validate = len(1..12289))]
text: String, text: String,
#[field(validate = len(0..33))] #[field(validate = len(0..97))]
cw: String, cw: String,
allow_search: Option<i8>, allow_search: Option<i8>,
use_title: Option<i8>, use_title: Option<i8>,
@ -52,7 +52,7 @@ pub struct PostOutput {
#[derive(FromForm)] #[derive(FromForm)]
pub struct CwInput { pub struct CwInput {
pid: i32, pid: i32,
#[field(validate = len(0..33))] #[field(validate = len(0..97))]
cw: String, cw: String,
} }
@ -145,6 +145,7 @@ pub async fn get_list(
Ok(json!({ Ok(json!({
"data": ps_data, "data": ps_data,
"count": ps_data.len(), "count": ps_data.len(),
"custom_title": CustomTitle::get(&rconn, &user.namehash).await?,
"code": 0 "code": 0
})) }))
} }
@ -162,7 +163,12 @@ pub async fn publish_post(
content: poi.text.to_string(), content: poi.text.to_string(),
cw: poi.cw.to_string(), cw: poi.cw.to_string(),
author_hash: user.namehash.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(), is_tmp: user.id.is_none(),
n_attentions: 1, n_attentions: 1,
allow_search: poi.allow_search.is_some(), 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::systemlog::get_systemlog,
api::operation::delete, api::operation::delete,
api::operation::report, api::operation::report,
api::operation::set_title,
api::operation::block, api::operation::block,
], ],
) )
@ -96,4 +97,5 @@ fn init_database() {
async fn clear_outdate_redis_data(rconn: &RdsConn) { async fn clear_outdate_redis_data(rconn: &RdsConn) {
rds_models::BannedUsers::clear(&rconn).await.unwrap(); 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_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";
const KEY_DANGEROUS_USERS: &str = "hole_thu:dangerous_users"; //兼容一下旧版 const KEY_DANGEROUS_USERS: &str = "hole_thu:dangerous_users"; //兼容一下旧版
const KEY_CUSTOM_TITLE: &str = "hole_v2:title";
const SYSTEMLOG_MAX_LEN: isize = 1000; const SYSTEMLOG_MAX_LEN: isize = 1000;
pub const BLOCK_THRESHOLD: i32 = 10; 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; pub(crate) use init;

Loading…
Cancel
Save