hyaenidae/src/browse.rs
2021-04-02 12:07:19 -05:00

170 lines
4.7 KiB
Rust

use crate::{
error::Error,
extensions::{ProfileExt, SubmissionExt},
images::ThumbnailImage,
middleware::UserProfile,
nav::NavState,
pagination::PageSource,
profiles::SubmissionPage,
submissions::pagination::{browse_page, Cache},
ActixLoader, State,
};
use actix_web::{web, HttpRequest, HttpResponse};
use hyaenidae_accounts::User;
use hyaenidae_toolkit::{Button, IndicatorColor, Thumbnail};
use i18n_embed_fl::fl;
use uuid::Uuid;
pub(crate) async fn index(
loader: ActixLoader,
req: HttpRequest,
page: Option<web::Query<SubmissionPage>>,
user: Option<User>,
profile: Option<UserProfile>,
nav_state: NavState,
state: web::Data<State>,
) -> Result<HttpResponse, Error> {
let profile = profile.map(|p| p.0);
if user.is_some() && profile.is_none() {
return Ok(crate::profiles::to_change_profile_page());
}
let viewer = profile.map(|p| p.id());
let view = ViewBrowseState::build(
req.path().to_owned(),
viewer,
page.map(|q| q.into_inner().into()),
&state,
)
.await?;
crate::rendered(HttpResponse::Ok(), |cursor| {
crate::templates::browse(cursor, &loader, &view, &nav_state)
})
}
pub struct ViewBrowseState {
cache: Cache,
submissions: Vec<Uuid>,
previous_id: Option<Uuid>,
next_id: Option<Uuid>,
logged_in: bool,
path: String,
reset: bool,
}
impl ViewBrowseState {
async fn build(
path: String,
viewer: Option<Uuid>,
source: Option<PageSource>,
state: &State,
) -> Result<Self, Error> {
let store = state.profiles.clone();
let can_view_sensitive = if let Some(viewer) = viewer {
state.settings.for_profile(viewer).await?.sensitive
} else {
false
};
let state = actix_web::web::block(move || {
let mut cache = Cache::new();
let page = browse_page(viewer, can_view_sensitive, &store, &mut cache, source);
ViewBrowseState {
cache,
submissions: page.items,
next_id: page.next,
previous_id: page.prev,
reset: page.reset,
logged_in: viewer.is_some(),
path,
}
})
.await?;
Ok(state)
}
pub(crate) fn has_submissions(&self) -> bool {
!self.submissions.is_empty()
}
pub(crate) fn is_logged_in(&self) -> bool {
self.logged_in
}
pub(crate) fn has_nav(&self) -> bool {
self.next_id.is_some() || self.previous_id.is_some()
}
pub(crate) fn submissions(&self) -> Vec<Thumbnail> {
self.submissions
.iter()
.filter_map(move |submission_id| {
let submission = self.cache.submission_map.get(&submission_id)?;
let author = self.cache.profile_map.get(&submission.profile_id())?;
let file_id = submission.files().get(0)?;
let file = self.cache.file_map.get(&file_id)?;
let key = file.pictrs_key()?;
let thumb = Thumbnail::new(
ThumbnailImage::new(key, &submission.title_text()),
&submission.view_path(),
)
.title(&submission.title_text())
.author(&author.name(), &author.view_path());
let sensitive_color = if submission.is_sensitive() {
Some(IndicatorColor::Red)
} else {
None
};
if submission.files().len() > 1 {
Some(thumb.indicator(
&format!("+{}", submission.files().len() - 1),
sensitive_color.unwrap_or(IndicatorColor::White),
))
} else {
if let Some(sensitive_color) = sensitive_color {
Some(thumb.indicator("", sensitive_color))
} else {
Some(thumb)
}
}
})
.collect()
}
pub(crate) fn nav(&self, loader: &ActixLoader) -> Vec<Button> {
let mut nav = vec![];
if let Some(prev) = self.previous_id {
nav.push(
Button::secondary(&fl!(loader, "previous-button"))
.href(&format!("{}?min={}", self.path, prev)),
);
}
if let Some(next) = self.next_id {
nav.push(
Button::secondary(&fl!(loader, "next-button"))
.href(&format!("{}?max={}", self.path, next)),
);
}
if self.reset {
nav.push(Button::secondary(&fl!(loader, "reset-button")).href(&self.path));
}
nav
}
}