Server: Expose NSFW toggle, Dark Mode toggle
Ensure all submission view permission logic is the same
This commit is contained in:
parent
81edfa7123
commit
010dd2952f
|
@ -66,10 +66,16 @@ impl ViewBrowseState {
|
|||
) -> 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, &store, &mut cache, source);
|
||||
let page = browse_page(viewer, can_view_sensitive, &store, &mut cache, source);
|
||||
|
||||
Ok(ViewBrowseState {
|
||||
cache,
|
||||
|
|
|
@ -163,16 +163,16 @@ fn can_view_logged_out(
|
|||
None => return Ok(false),
|
||||
};
|
||||
|
||||
if submission.is_followers_only() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let submissioner = match store.store.profiles.by_id(submission.profile_id())? {
|
||||
Some(s) => s,
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
if submissioner.login_required() {
|
||||
if crate::pagination::submission::can_view(
|
||||
None,
|
||||
&submission,
|
||||
&store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
|
@ -217,6 +217,7 @@ fn can_view_comment_logged_out_no_recurse(
|
|||
|
||||
fn can_view(
|
||||
profile: &Profile,
|
||||
can_view_sensitive: bool,
|
||||
comment: &Comment,
|
||||
store: &hyaenidae_profiles::State,
|
||||
) -> Result<bool, Error> {
|
||||
|
@ -225,47 +226,19 @@ fn can_view(
|
|||
None => return Ok(false),
|
||||
};
|
||||
|
||||
let submissioner_id = submission.profile_id();
|
||||
|
||||
let blocking_submissioner = store
|
||||
.store
|
||||
.view
|
||||
.blocks
|
||||
.by_forward(submissioner_id, profile.id())?
|
||||
.is_some();
|
||||
|
||||
if blocking_submissioner {
|
||||
if crate::pagination::submission::can_view(
|
||||
Some(profile.id()),
|
||||
&submission,
|
||||
&store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
can_view_sensitive,
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let blocked_by_submissioner = store
|
||||
.store
|
||||
.view
|
||||
.blocks
|
||||
.by_forward(profile.id(), submissioner_id)?
|
||||
.is_some();
|
||||
|
||||
if blocked_by_submissioner {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if submission.is_followers_only() {
|
||||
let is_submissioner = profile.id() == submissioner_id;
|
||||
|
||||
if !is_submissioner {
|
||||
let follows_submissioner = store
|
||||
.store
|
||||
.view
|
||||
.follows
|
||||
.by_forward(submissioner_id, profile.id())?
|
||||
.is_some();
|
||||
|
||||
if !follows_submissioner {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
can_view_comment(profile, comment, store)
|
||||
}
|
||||
|
||||
|
@ -325,8 +298,14 @@ async fn prepare_view(
|
|||
profile: Option<&Profile>,
|
||||
state: &State,
|
||||
) -> Result<Option<CommentView>, Error> {
|
||||
let can_view_sensitive = if let Some(profile) = profile {
|
||||
state.settings.for_profile(profile.id()).await?.sensitive
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
match profile {
|
||||
Some(profile) if !can_view(&profile, &comment, &state.profiles)? => {
|
||||
Some(profile) if !can_view(&profile, can_view_sensitive, &comment, &state.profiles)? => {
|
||||
return Ok(None);
|
||||
}
|
||||
None if !can_view_logged_out(&comment, &state.profiles)? => {
|
||||
|
@ -550,7 +529,9 @@ async fn reply(
|
|||
None => return Ok(crate::to_404()),
|
||||
};
|
||||
|
||||
if !can_view(&profile, &comment, &state.profiles)? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if !can_view(&profile, can_view_sensitive, &comment, &state.profiles)? {
|
||||
return Ok(crate::to_404());
|
||||
}
|
||||
|
||||
|
@ -738,7 +719,9 @@ async fn report_page(
|
|||
None => return Ok(crate::to_404()),
|
||||
};
|
||||
|
||||
if !can_view(&profile, &comment, &state.profiles)? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if !can_view(&profile, can_view_sensitive, &comment, &state.profiles)? {
|
||||
return Ok(crate::to_404());
|
||||
}
|
||||
|
||||
|
@ -775,7 +758,9 @@ async fn report(
|
|||
None => return Ok(crate::to_404()),
|
||||
};
|
||||
|
||||
if !can_view(&profile, &comment, &state.profiles)? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if !can_view(&profile, can_view_sensitive, &comment, &state.profiles)? {
|
||||
return Ok(crate::to_404());
|
||||
}
|
||||
|
||||
|
@ -828,7 +813,9 @@ async fn report_success_page(
|
|||
None => return Ok(crate::to_404()),
|
||||
};
|
||||
|
||||
if !can_view(&profile, &comment, &state.profiles)? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if !can_view(&profile, can_view_sensitive, &comment, &state.profiles)? {
|
||||
return Ok(crate::to_404());
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ struct State {
|
|||
spawn: jobs::Spawn,
|
||||
apub: apub::Apub,
|
||||
images: images::Images,
|
||||
settings: profiles::SettingStore,
|
||||
domain: String,
|
||||
base_url: url::Url,
|
||||
db: Db,
|
||||
|
@ -240,6 +241,7 @@ impl State {
|
|||
let domain = base_url.domain().req()?.to_owned();
|
||||
|
||||
let admin = admin::Store::build(db)?;
|
||||
let settings = profiles::SettingStore::build(db)?;
|
||||
|
||||
Ok(State {
|
||||
profiles: hyaenidae_profiles::State::build(
|
||||
|
@ -254,6 +256,7 @@ impl State {
|
|||
spawn,
|
||||
apub,
|
||||
images,
|
||||
settings,
|
||||
base_url,
|
||||
domain,
|
||||
db: db.clone(),
|
||||
|
|
|
@ -63,6 +63,12 @@ impl FromRequest for NavState {
|
|||
format!("{}?show_nav=true", path)
|
||||
};
|
||||
|
||||
let dark = if let Some(profile) = &profile {
|
||||
state.settings.for_profile(profile.id()).await?.dark
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let notification_count = if let Some(profile) = &profile {
|
||||
total_for_profile(profile.id(), &state).await.ok()
|
||||
} else {
|
||||
|
@ -99,7 +105,7 @@ impl FromRequest for NavState {
|
|||
admin,
|
||||
href,
|
||||
is_open,
|
||||
dark: true,
|
||||
dark,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -22,12 +22,14 @@ impl Cache {
|
|||
|
||||
pub(crate) fn browse_page(
|
||||
viewer: Option<Uuid>,
|
||||
can_view_sensitive: bool,
|
||||
store: &hyaenidae_profiles::State,
|
||||
cache: &mut Cache,
|
||||
source: Option<PageSource>,
|
||||
) -> Page {
|
||||
Page::from_pagination(
|
||||
BrowsePager {
|
||||
can_view_sensitive,
|
||||
viewer,
|
||||
store,
|
||||
cache,
|
||||
|
@ -39,6 +41,7 @@ pub(crate) fn browse_page(
|
|||
|
||||
pub(crate) fn draft_page(
|
||||
viewer: Option<Uuid>,
|
||||
can_view_sensitive: bool,
|
||||
profile_id: Uuid,
|
||||
store: &hyaenidae_profiles::State,
|
||||
cache: &mut Cache,
|
||||
|
@ -46,6 +49,7 @@ pub(crate) fn draft_page(
|
|||
) -> Page {
|
||||
Page::from_pagination(
|
||||
DraftPager {
|
||||
can_view_sensitive,
|
||||
viewer,
|
||||
profile_id,
|
||||
store,
|
||||
|
@ -58,6 +62,7 @@ pub(crate) fn draft_page(
|
|||
|
||||
pub(crate) fn main_page(
|
||||
viewer: Option<Uuid>,
|
||||
can_view_sensitive: bool,
|
||||
profile_id: Uuid,
|
||||
store: &hyaenidae_profiles::State,
|
||||
cache: &mut Cache,
|
||||
|
@ -65,6 +70,7 @@ pub(crate) fn main_page(
|
|||
) -> Page {
|
||||
Page::from_pagination(
|
||||
SubmissionPager {
|
||||
can_view_sensitive,
|
||||
viewer,
|
||||
profile_id,
|
||||
store,
|
||||
|
@ -76,6 +82,7 @@ pub(crate) fn main_page(
|
|||
}
|
||||
|
||||
struct BrowsePager<'b> {
|
||||
can_view_sensitive: bool,
|
||||
viewer: Option<Uuid>,
|
||||
store: &'b hyaenidae_profiles::State,
|
||||
cache: &'b mut Cache,
|
||||
|
@ -93,6 +100,7 @@ impl<'b> Pagination for BrowsePager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
false,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -108,6 +116,7 @@ impl<'b> Pagination for BrowsePager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
false,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -123,12 +132,14 @@ impl<'b> Pagination for BrowsePager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
false,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct DraftPager<'b> {
|
||||
can_view_sensitive: bool,
|
||||
viewer: Option<Uuid>,
|
||||
profile_id: Uuid,
|
||||
store: &'b hyaenidae_profiles::State,
|
||||
|
@ -147,6 +158,7 @@ impl<'b> Pagination for DraftPager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
true,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -162,6 +174,7 @@ impl<'b> Pagination for DraftPager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
true,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -177,12 +190,14 @@ impl<'b> Pagination for DraftPager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
true,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct SubmissionPager<'b> {
|
||||
can_view_sensitive: bool,
|
||||
viewer: Option<Uuid>,
|
||||
profile_id: Uuid,
|
||||
store: &'b hyaenidae_profiles::State,
|
||||
|
@ -201,6 +216,7 @@ impl<'b> Pagination for SubmissionPager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
true,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -216,6 +232,7 @@ impl<'b> Pagination for SubmissionPager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
true,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -231,6 +248,7 @@ impl<'b> Pagination for SubmissionPager<'b> {
|
|||
&self.store.store,
|
||||
self.cache,
|
||||
true,
|
||||
self.can_view_sensitive,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@ -241,6 +259,7 @@ fn filter_submissions<'a>(
|
|||
store: &'a hyaenidae_profiles::store::Store,
|
||||
cache: &'a mut Cache,
|
||||
show_unlisted: bool,
|
||||
can_view_sensitive: bool,
|
||||
) -> impl FnMut(Uuid) -> Option<Uuid> + 'a {
|
||||
move |submission_id| {
|
||||
if !cache.submission_map.contains_key(&submission_id) {
|
||||
|
@ -251,7 +270,14 @@ fn filter_submissions<'a>(
|
|||
cache.profile_map.insert(profile.id(), profile);
|
||||
}
|
||||
|
||||
let opt = can_view(viewer, &submission, store, cache, show_unlisted);
|
||||
let opt = can_view(
|
||||
viewer,
|
||||
&submission,
|
||||
store,
|
||||
cache,
|
||||
show_unlisted,
|
||||
can_view_sensitive,
|
||||
);
|
||||
|
||||
if let Some(file_id) = submission.files().get(0) {
|
||||
if !cache.file_map.contains_key(file_id) {
|
||||
|
@ -266,7 +292,14 @@ fn filter_submissions<'a>(
|
|||
} else {
|
||||
let submission = cache.submission_map.get(&submission_id)?.clone();
|
||||
|
||||
can_view(viewer, &submission, store, cache, show_unlisted)?;
|
||||
can_view(
|
||||
viewer,
|
||||
&submission,
|
||||
store,
|
||||
cache,
|
||||
show_unlisted,
|
||||
can_view_sensitive,
|
||||
)?;
|
||||
|
||||
Some(submission_id)
|
||||
}
|
||||
|
@ -279,11 +312,17 @@ pub(crate) fn can_view(
|
|||
store: &hyaenidae_profiles::store::Store,
|
||||
cache: &mut Cache,
|
||||
show_unlisted: bool,
|
||||
can_view_sensitive: bool,
|
||||
) -> Option<()> {
|
||||
if let Some(viewer) = viewer {
|
||||
if viewer == submission.profile_id() {
|
||||
return Some(());
|
||||
}
|
||||
|
||||
if submission.is_sensitive() && !can_view_sensitive {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(block) = cache.blocks.get(&submission.profile_id()) {
|
||||
if *block {
|
||||
return None;
|
||||
|
|
|
@ -15,9 +15,11 @@ use i18n_embed_fl::fl;
|
|||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
mod settings;
|
||||
mod state;
|
||||
mod update;
|
||||
|
||||
pub(crate) use settings::{SettingStore, Settings};
|
||||
pub use state::{EditProfileState, ViewProfileState};
|
||||
pub use update::HandleState;
|
||||
|
||||
|
|
52
src/profiles/settings.rs
Normal file
52
src/profiles/settings.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use crate::error::Error;
|
||||
use sled::{Db, Tree};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub(crate) struct Settings {
|
||||
pub(crate) dark: bool,
|
||||
pub(crate) sensitive: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct SettingStore {
|
||||
tree: Tree,
|
||||
}
|
||||
|
||||
impl SettingStore {
|
||||
pub(crate) fn build(db: &Db) -> Result<Self, sled::Error> {
|
||||
Ok(SettingStore {
|
||||
tree: db.open_tree("/main/settings")?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn for_profile(&self, profile_id: Uuid) -> Result<Settings, Error> {
|
||||
let this = self.clone();
|
||||
|
||||
let opt = actix_web::web::block(move || {
|
||||
Ok(this
|
||||
.tree
|
||||
.get(profile_id.as_bytes())?
|
||||
.and_then(|ivec| serde_json::from_slice(&ivec).ok()))
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(opt.unwrap_or(Settings {
|
||||
dark: true,
|
||||
sensitive: false,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) async fn update(&self, profile_id: Uuid, settings: Settings) -> Result<(), Error> {
|
||||
let this = self.clone();
|
||||
|
||||
actix_web::web::block(move || {
|
||||
let vec = serde_json::to_vec(&settings)?;
|
||||
this.tree.insert(profile_id.as_bytes(), vec)?;
|
||||
Ok(()) as Result<_, Error>
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use crate::{
|
|||
submission::{draft_page, main_page, Cache},
|
||||
PageSource,
|
||||
},
|
||||
profiles::settings::Settings,
|
||||
views::ProfileView,
|
||||
ActixLoader, State,
|
||||
};
|
||||
|
@ -44,6 +45,8 @@ pub struct EditProfileState {
|
|||
pub(crate) banner_error: Option<String>,
|
||||
login_required_value: Option<bool>,
|
||||
pub(crate) login_required_error: Option<String>,
|
||||
pub(crate) settings_error: Option<String>,
|
||||
pub(crate) settings: Settings,
|
||||
}
|
||||
|
||||
impl ViewProfileState {
|
||||
|
@ -226,6 +229,12 @@ impl ViewProfileState {
|
|||
) -> 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();
|
||||
|
||||
|
@ -248,9 +257,23 @@ impl ViewProfileState {
|
|||
cache.profile_map.insert(profile.id(), profile);
|
||||
|
||||
let page = if drafts {
|
||||
draft_page(viewer, profile_id, &store, &mut cache, source)
|
||||
draft_page(
|
||||
viewer,
|
||||
can_view_sensitive,
|
||||
profile_id,
|
||||
&store,
|
||||
&mut cache,
|
||||
source,
|
||||
)
|
||||
} else {
|
||||
main_page(viewer, profile_id, &store, &mut cache, source)
|
||||
main_page(
|
||||
viewer,
|
||||
can_view_sensitive,
|
||||
profile_id,
|
||||
&store,
|
||||
&mut cache,
|
||||
source,
|
||||
)
|
||||
};
|
||||
|
||||
let is_self = viewer.map(|id| id == profile_id).unwrap_or(false);
|
||||
|
@ -308,7 +331,12 @@ impl ViewProfileState {
|
|||
}
|
||||
|
||||
impl EditProfileState {
|
||||
pub(super) fn new(profile: Profile, icon: Option<File>, banner: Option<File>) -> Self {
|
||||
pub(super) fn new(
|
||||
profile: Profile,
|
||||
icon: Option<File>,
|
||||
banner: Option<File>,
|
||||
settings: Settings,
|
||||
) -> Self {
|
||||
EditProfileState {
|
||||
profile,
|
||||
icon,
|
||||
|
@ -321,6 +349,8 @@ impl EditProfileState {
|
|||
banner_error: None,
|
||||
login_required_value: None,
|
||||
login_required_error: None,
|
||||
settings_error: None,
|
||||
settings,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -330,6 +360,8 @@ impl EditProfileState {
|
|||
let icon_id = profile.icon();
|
||||
let banner_id = profile.banner();
|
||||
|
||||
let settings = state.settings.for_profile(profile.id()).await?;
|
||||
|
||||
let (icon, banner) = actix_web::web::block(move || {
|
||||
let icon = if let Some(id) = icon_id {
|
||||
store.store.files.by_id(id)?
|
||||
|
@ -346,7 +378,7 @@ impl EditProfileState {
|
|||
})
|
||||
.await?;
|
||||
|
||||
Ok(Self::new(profile, icon, banner))
|
||||
Ok(Self::new(profile, icon, banner, settings))
|
||||
}
|
||||
|
||||
pub(crate) fn profile<'a>(&'a self) -> ProfileView<'a> {
|
||||
|
@ -497,4 +529,9 @@ impl EditProfileState {
|
|||
self.login_required_error = Some(err.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub(super) fn settings_error(&mut self, err: String) -> &mut Self {
|
||||
self.settings_error = Some(err);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
error::{Error, OptionExt},
|
||||
middleware::{ProfileData, UserProfile},
|
||||
nav::NavState,
|
||||
profiles::{state::EditProfileState, to_current_profile},
|
||||
profiles::{settings::Settings, state::EditProfileState, to_current_profile},
|
||||
ActixLoader, State,
|
||||
};
|
||||
use actix_session::Session;
|
||||
|
@ -66,6 +66,11 @@ pub(super) fn update_scope() -> Scope {
|
|||
.route(web::post().to(update_require_login))
|
||||
.route(web::get().to(to_current_profile)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/settings")
|
||||
.route(web::post().to(update_settings))
|
||||
.route(web::get().to(to_current_profile)),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn to_create() -> HttpResponse {
|
||||
|
@ -328,6 +333,39 @@ async fn update_require_login(
|
|||
})
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct SettingsForm {
|
||||
sensitive: Option<String>,
|
||||
dark: Option<String>,
|
||||
}
|
||||
|
||||
async fn update_settings(
|
||||
loader: ActixLoader,
|
||||
form: web::Form<SettingsForm>,
|
||||
profile: UserProfile,
|
||||
nav_state: NavState,
|
||||
state: web::Data<State>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
let profile = profile.0;
|
||||
|
||||
let settings = Settings {
|
||||
sensitive: form.sensitive.is_some(),
|
||||
dark: form.dark.is_some(),
|
||||
};
|
||||
|
||||
let error = match state.settings.update(profile.id(), settings).await {
|
||||
Ok(_) => return Ok(to_current_profile()),
|
||||
Err(e) => e.to_string(),
|
||||
};
|
||||
|
||||
let mut profile_state = EditProfileState::for_profile(profile, &state).await?;
|
||||
profile_state.settings_error(error);
|
||||
|
||||
crate::rendered(HttpResponse::InternalServerError(), |cursor| {
|
||||
crate::templates::profiles::current(cursor, &loader, &profile_state, &nav_state)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
pub struct HandleForm {
|
||||
pub(crate) handle: String,
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
images::{largest_image, FullImage, ImageType},
|
||||
middleware::{CurrentSubmission, UserProfile},
|
||||
nav::NavState,
|
||||
profiles::Settings,
|
||||
views::{OwnedProfileView, OwnedSubmissionView},
|
||||
ActixLoader, State,
|
||||
};
|
||||
|
@ -195,7 +196,16 @@ async fn report_page(
|
|||
|
||||
let view = ReportView::build(submission_id.into_inner(), &state).await?;
|
||||
|
||||
if let Some(res) = can_view(Some(profile.id()), &view.author, &view.submission, &state).await? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if let Some(res) = can_view(
|
||||
Some(profile.id()),
|
||||
can_view_sensitive,
|
||||
&view.submission,
|
||||
&state,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
|
@ -223,7 +233,16 @@ async fn report(
|
|||
|
||||
let mut view = ReportView::build(submission_id.into_inner(), &state).await?;
|
||||
|
||||
if let Some(res) = can_view(Some(profile.id()), &view.author, &view.submission, &state).await? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if let Some(res) = can_view(
|
||||
Some(profile.id()),
|
||||
can_view_sensitive,
|
||||
&view.submission,
|
||||
&state,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
|
@ -267,7 +286,16 @@ async fn report_success_page(
|
|||
|
||||
let view = ReportView::build(submission_id.into_inner(), &state).await?;
|
||||
|
||||
if let Some(res) = can_view(Some(profile.id()), &view.author, &view.submission, &state).await? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if let Some(res) = can_view(
|
||||
Some(profile.id()),
|
||||
can_view_sensitive,
|
||||
&view.submission,
|
||||
&state,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
|
@ -293,12 +321,15 @@ pub struct SubmissionState {
|
|||
pub(crate) delete_error: Option<String>,
|
||||
pub(crate) visibility_error: Option<String>,
|
||||
pub(crate) sensitive_error: Option<String>,
|
||||
pub(crate) settings: Settings,
|
||||
}
|
||||
|
||||
impl SubmissionState {
|
||||
async fn new(submission: Submission, state: &State) -> Result<Self, Error> {
|
||||
let file_ids: Vec<Uuid> = submission.files().iter().copied().collect();
|
||||
|
||||
let settings = state.settings.for_profile(submission.profile_id()).await?;
|
||||
|
||||
let store = state.profiles.clone();
|
||||
let files = web::block(move || {
|
||||
let mut files = HashMap::new();
|
||||
|
@ -327,6 +358,7 @@ impl SubmissionState {
|
|||
delete_error: None,
|
||||
visibility_error: None,
|
||||
sensitive_error: None,
|
||||
settings,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -613,53 +645,30 @@ impl ViewSubmissionState {
|
|||
|
||||
async fn can_view(
|
||||
viewer: Option<Uuid>,
|
||||
poster: &Profile,
|
||||
can_view_sensitive: bool,
|
||||
submission: &Submission,
|
||||
state: &State,
|
||||
) -> Result<Option<HttpResponse>, Error> {
|
||||
if submission.is_sensitive() {
|
||||
if viewer.is_none() {
|
||||
let store = state.profiles.clone();
|
||||
let submission = submission.clone();
|
||||
let opt = web::block(move || {
|
||||
Ok(crate::pagination::submission::can_view(
|
||||
viewer,
|
||||
&submission,
|
||||
&store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
can_view_sensitive,
|
||||
)) as Result<Option<()>, Error>
|
||||
})
|
||||
.await?;
|
||||
|
||||
if opt.is_none() {
|
||||
return Ok(Some(crate::to_404()));
|
||||
}
|
||||
}
|
||||
|
||||
if poster.login_required() && viewer.is_none() {
|
||||
return Ok(Some(crate::to_404()));
|
||||
}
|
||||
|
||||
if poster.local_owner().is_none() && viewer.is_none() {
|
||||
return Ok(Some(crate::to_404()));
|
||||
}
|
||||
|
||||
let is_self = viewer
|
||||
.as_ref()
|
||||
.map(|pid| *pid == poster.id())
|
||||
.unwrap_or(false);
|
||||
|
||||
if submission.published().is_none() && !is_self {
|
||||
return Ok(Some(crate::to_404()));
|
||||
}
|
||||
|
||||
let is_follower_or_self = if let Some(pid) = viewer {
|
||||
let is_follower = state
|
||||
.profiles
|
||||
.store
|
||||
.view
|
||||
.follows
|
||||
.by_forward(poster.id(), pid)?
|
||||
.is_some();
|
||||
|
||||
is_follower || is_self
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if submission.is_followers_only() && !is_follower_or_self {
|
||||
return Ok(Some(crate::to_404()));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn files_for_submission(
|
||||
submission: &Submission,
|
||||
|
@ -746,6 +755,7 @@ fn submission_nav(
|
|||
|
||||
async fn adjacent_submissions(
|
||||
viewer: Option<Uuid>,
|
||||
can_view_sensitive: bool,
|
||||
submission: &Submission,
|
||||
state: &State,
|
||||
) -> Result<(Option<Uuid>, Option<Uuid>), Error> {
|
||||
|
@ -769,6 +779,7 @@ async fn adjacent_submissions(
|
|||
&inner_store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
can_view_sensitive,
|
||||
)
|
||||
.map(move |_| id)
|
||||
});
|
||||
|
@ -787,6 +798,7 @@ async fn adjacent_submissions(
|
|||
&store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
can_view_sensitive,
|
||||
)
|
||||
.map(move |_| id)
|
||||
});
|
||||
|
@ -808,6 +820,7 @@ async fn adjacent_submissions(
|
|||
&inner_store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
can_view_sensitive,
|
||||
)
|
||||
.map(move |_| id)
|
||||
});
|
||||
|
@ -826,6 +839,7 @@ async fn adjacent_submissions(
|
|||
&store.store,
|
||||
&mut Default::default(),
|
||||
true,
|
||||
can_view_sensitive,
|
||||
)
|
||||
.map(move |_| id)
|
||||
});
|
||||
|
@ -862,12 +876,18 @@ async fn submission_page(
|
|||
let cache = files_for_submission(&submission, cache, &state).await?;
|
||||
let cache = files_for_profile(&poster, cache, &state).await?;
|
||||
|
||||
if let Some(res) = can_view(viewer, &poster, &submission, &state).await? {
|
||||
let can_view_sensitive = if let Some(viewer) = viewer {
|
||||
state.settings.for_profile(viewer).await?.sensitive
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if let Some(res) = can_view(viewer, can_view_sensitive, &submission, &state).await? {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let (next_submission, previous_submission) =
|
||||
adjacent_submissions(viewer, &submission, &state).await?;
|
||||
adjacent_submissions(viewer, can_view_sensitive, &submission, &state).await?;
|
||||
|
||||
let (nav, current_file) = submission_nav(
|
||||
page.map(|p| p.into_inner()),
|
||||
|
@ -969,7 +989,10 @@ async fn create_comment(
|
|||
let poster_id = submission.profile_id();
|
||||
let poster = web::block(move || store.store.profiles.by_id(poster_id)?.req()).await?;
|
||||
|
||||
if let Some(res) = can_view(Some(profile.id()), &poster, &submission, &state).await? {
|
||||
let can_view_sensitive = state.settings.for_profile(profile.id()).await?.sensitive;
|
||||
|
||||
if let Some(res) = can_view(Some(profile.id()), can_view_sensitive, &submission, &state).await?
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
|
@ -999,7 +1022,7 @@ async fn create_comment(
|
|||
let cache = files_for_profile(&poster, cache, &state).await?;
|
||||
|
||||
let (next_submission, previous_submission) =
|
||||
adjacent_submissions(Some(profile.id()), &submission, &state).await?;
|
||||
adjacent_submissions(Some(profile.id()), can_view_sensitive, &submission, &state).await?;
|
||||
|
||||
let (nav, current_file) = submission_nav(
|
||||
page.map(|p| p.into_inner()),
|
||||
|
|
|
@ -30,6 +30,27 @@
|
|||
@:button_group(&state.buttons(loader))
|
||||
})
|
||||
})
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="/profiles/update/settings">
|
||||
@:card_title({
|
||||
@fl!(loader, "update-settings-heading")
|
||||
})
|
||||
@if let Some(error) = &state.settings_error {
|
||||
@:card_body({
|
||||
@error
|
||||
})
|
||||
}
|
||||
@:card_body({
|
||||
@:checkbox("sensitive", &fl!(loader, "sensitive-checkbox"), state.settings.sensitive)
|
||||
@:checkbox("dark", &fl!(loader, "dark-checkbox"), state.settings.dark)
|
||||
})
|
||||
@:card_body({
|
||||
@:button_group(&[
|
||||
Button::primary(&fl!(loader, "update-settings-button")),
|
||||
])
|
||||
})
|
||||
</form>
|
||||
})
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
@:card_title({
|
||||
@fl!(loader, "update-profile-heading")
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
</form>
|
||||
})
|
||||
}
|
||||
@if state.settings.sensitive {
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="@state.sensitive_path()">
|
||||
@:card_title({
|
||||
|
@ -85,6 +86,7 @@
|
|||
})
|
||||
</form>
|
||||
})
|
||||
}
|
||||
@:card(&Card::full_width().dark(nav_state.dark()), {
|
||||
<form method="POST" action="@state.update_path()">
|
||||
@:card_title({
|
||||
|
|
|
@ -138,6 +138,12 @@ file-num = file {$num}
|
|||
|
||||
profile-settings-title = Profile Settings
|
||||
profile-settings-subtitle = Edit {$profileName}'s profile on {site-name}
|
||||
|
||||
update-settings-heading = Update Profile Settings
|
||||
sensitive-checkbox = Show me NSFW content
|
||||
dark-checkbox = Enable dark mode
|
||||
update-settings-button = Save
|
||||
|
||||
update-profile-heading = Update Profile
|
||||
update-bio-heading = Update Bio
|
||||
update-bio-description =
|
||||
|
|
Loading…
Reference in a new issue