16 changed files with 495 additions and 211 deletions
@ -0,0 +1,63 @@ |
|||||||
|
use crate::api::post::ps2outputs; |
||||||
|
use crate::api::{APIError, CurrentUser, MapToAPIError, PolicyError::*, API, UGC}; |
||||||
|
use crate::db_conn::Db; |
||||||
|
use crate::models::*; |
||||||
|
use crate::rds_conn::RdsConn; |
||||||
|
use crate::rds_models::*; |
||||||
|
use rocket::form::Form; |
||||||
|
use rocket::serde::json::{json, Value}; |
||||||
|
|
||||||
|
#[derive(FromForm)] |
||||||
|
pub struct AttentionInput { |
||||||
|
pid: i32, |
||||||
|
#[field(validate = range(0..2))] |
||||||
|
switch: i32, |
||||||
|
} |
||||||
|
|
||||||
|
#[post("/attention", data = "<ai>")] |
||||||
|
pub async fn attention_post( |
||||||
|
ai: Form<AttentionInput>, |
||||||
|
user: CurrentUser, |
||||||
|
db: Db, |
||||||
|
rconn: RdsConn, |
||||||
|
) -> API<Value> { |
||||||
|
user.id.ok_or_else(|| APIError::PcError(NotAllowed))?; |
||||||
|
let p = Post::get(&db, ai.pid).await.m()?; |
||||||
|
p.check_permission(&user, "r")?; |
||||||
|
let mut att = Attention::init(&user.namehash, rconn); |
||||||
|
let switch_to = ai.switch == 1; |
||||||
|
let mut delta: i32 = 0; |
||||||
|
if att.has(ai.pid).await.m()? != switch_to { |
||||||
|
if switch_to { |
||||||
|
att.add(ai.pid).await.m()?; |
||||||
|
delta = 1; |
||||||
|
} else { |
||||||
|
att.remove(ai.pid).await.m()?; |
||||||
|
delta = -1; |
||||||
|
} |
||||||
|
p.change_n_attentions(&db, delta).await.m()?; |
||||||
|
} |
||||||
|
|
||||||
|
Ok(json!({ |
||||||
|
"code": 0, |
||||||
|
"attention": ai.switch == 1, |
||||||
|
"n_attentions": p.n_attentions + delta, |
||||||
|
// for old version frontend
|
||||||
|
"likenum": p.n_attentions + delta, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
#[get("/getattention")] |
||||||
|
pub async fn get_attention(user: CurrentUser, db: Db, rconn: RdsConn) -> API<Value> { |
||||||
|
let ids = Attention::init(&user.namehash, rconn.clone()) |
||||||
|
.all() |
||||||
|
.await |
||||||
|
.m()?; |
||||||
|
let ps = Post::get_multi(&db, ids).await.m()?; |
||||||
|
let ps_data = ps2outputs(&ps, &user, &db, rconn.clone()).await; |
||||||
|
|
||||||
|
Ok(json!({ |
||||||
|
"code": 0, |
||||||
|
"data": ps_data, |
||||||
|
})) |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
use redis::aio::MultiplexedConnection; |
||||||
|
use rocket::request::{FromRequest, Outcome, Request}; |
||||||
|
use std::ops::{Deref, DerefMut}; |
||||||
|
use std::env; |
||||||
|
|
||||||
|
pub struct RdsConn(pub MultiplexedConnection); |
||||||
|
|
||||||
|
#[rocket::async_trait] |
||||||
|
impl<'r> FromRequest<'r> for RdsConn { |
||||||
|
type Error = (); |
||||||
|
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { |
||||||
|
let rconn = request.rocket().state::<MultiplexedConnection>().unwrap(); |
||||||
|
Outcome::Success(RdsConn(rconn.clone())) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Clone for RdsConn { |
||||||
|
fn clone(&self) -> Self { |
||||||
|
RdsConn(self.0.clone()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Deref for RdsConn { |
||||||
|
type Target = MultiplexedConnection; |
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target { |
||||||
|
&self.0 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl DerefMut for RdsConn { |
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target { |
||||||
|
&mut self.0 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
pub async fn init_rds_client() -> MultiplexedConnection { |
||||||
|
let redis_url = env::var("REDIS_URL").expect("REDIS_URL must be set"); |
||||||
|
let client = redis::Client::open(redis_url).expect("connect to redis fail"); |
||||||
|
client.get_multiplexed_async_connection().await.unwrap() |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
use crate::rds_conn::RdsConn; |
||||||
|
use redis::{AsyncCommands, RedisResult}; |
||||||
|
|
||||||
|
pub struct Attention { |
||||||
|
key: String, |
||||||
|
rconn: RdsConn, |
||||||
|
} |
||||||
|
|
||||||
|
impl Attention { |
||||||
|
pub fn init(namehash: &str, rconn: RdsConn) -> Self { |
||||||
|
Attention { |
||||||
|
key: format!("hole_v2:attention:{}", namehash), |
||||||
|
rconn: rconn, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn add(&mut self, pid: i32) -> RedisResult<()> { |
||||||
|
self.rconn.sadd(&self.key, pid).await |
||||||
|
} |
||||||
|
|
||||||
|
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<bool> { |
||||||
|
self.rconn.sismember(&self.key, pid).await |
||||||
|
} |
||||||
|
|
||||||
|
pub async fn all(&mut self) -> RedisResult<Vec<i32>> { |
||||||
|
self.rconn.smembers(&self.key).await |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue