//! `User` struct and related functionality // #[cfg(test)] // mod mock_postgres; // #[cfg(test)] // use mock_postgres as postgres; // #[cfg(not(test))] use super::postgres::PgPool; use super::query::Query; use super::{Content, Reach, Stream, Timeline}; use crate::event::Id; use hashbrown::HashSet; use warp::reject::Rejection; #[derive(Clone, Debug, PartialEq)] pub struct Subscription { pub timeline: Timeline, pub(crate) allowed_langs: HashSet, pub(crate) blocks: Blocks, pub(crate) hashtag_name: Option, pub access_token: Option, } #[derive(Clone, Default, Debug, PartialEq)] pub(crate) struct Blocks { pub(crate) blocked_domains: HashSet, pub(crate) blocked_users: HashSet, pub(crate) blocking_users: HashSet, } impl Default for Subscription { fn default() -> Self { Self { timeline: Timeline(Stream::Unset, Reach::Local, Content::Notification), allowed_langs: HashSet::new(), blocks: Blocks::default(), hashtag_name: None, access_token: None, } } } impl Subscription { pub(super) fn query_postgres(q: Query, pool: PgPool) -> Result { let user = pool.clone().select_user(&q.access_token)?; let timeline = { let tl = Timeline::from_query_and_user(&q, &user)?; let pool = pool.clone(); use Stream::*; match tl { Timeline(Hashtag(_), reach, stream) => { let tag = pool.select_hashtag_id(&q.hashtag)?; Timeline(Hashtag(tag), reach, stream) } Timeline(List(list_id), _, _) if !pool.user_owns_list(user.id, list_id)? => { Err(warp::reject::custom("Error: Missing access token"))? } other_tl => other_tl, } }; let hashtag_name = match timeline { Timeline(Stream::Hashtag(_), _, _) => Some(q.hashtag), _non_hashtag_timeline => None, }; Ok(Subscription { timeline, allowed_langs: user.allowed_langs, blocks: Blocks { blocking_users: pool.clone().select_blocking_users(user.id)?, blocked_users: pool.clone().select_blocked_users(user.id)?, blocked_domains: pool.select_blocked_domains(user.id)?, }, hashtag_name, access_token: q.access_token, }) } }