Server: Expose visibility on submission update page
Make submission next/previous buttons respect visibility
This commit is contained in:
parent
2a85cb6661
commit
d3e62b7cd1
|
@ -927,16 +927,14 @@ impl ReportView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn select(&self, loader: &ActixLoader) -> Select {
|
pub(crate) fn select(&self, loader: &ActixLoader) -> Select {
|
||||||
let select = Select::new("action")
|
Select::new("action")
|
||||||
.title(&fl!(loader, "admin-report-resolve-select"))
|
.title(&fl!(loader, "admin-report-resolve-select"))
|
||||||
.options(&[
|
.options(&[
|
||||||
(&fl!(loader, "admin-report-ignore"), "Ignore"),
|
(&fl!(loader, "admin-report-ignore"), "Ignore"),
|
||||||
(&fl!(loader, "admin-report-delete"), "Delete"),
|
(&fl!(loader, "admin-report-delete"), "Delete"),
|
||||||
(&fl!(loader, "admin-report-suspend"), "Suspend"),
|
(&fl!(loader, "admin-report-suspend"), "Suspend"),
|
||||||
])
|
])
|
||||||
.default_option("Ignore");
|
.default_option("Ignore")
|
||||||
|
|
||||||
select
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn input(&self, loader: &ActixLoader) -> TextInput {
|
pub(crate) fn input(&self, loader: &ActixLoader) -> TextInput {
|
||||||
|
|
|
@ -92,6 +92,7 @@ impl<'b> Pagination for BrowsePager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
false,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -106,6 +107,7 @@ impl<'b> Pagination for BrowsePager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
false,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -120,6 +122,7 @@ impl<'b> Pagination for BrowsePager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
false,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -143,6 +146,7 @@ impl<'b> Pagination for DraftPager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
true,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -157,6 +161,7 @@ impl<'b> Pagination for DraftPager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
true,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -171,6 +176,7 @@ impl<'b> Pagination for DraftPager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
true,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -194,6 +200,7 @@ impl<'b> Pagination for SubmissionPager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
true,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -208,6 +215,7 @@ impl<'b> Pagination for SubmissionPager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
true,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -222,6 +230,7 @@ impl<'b> Pagination for SubmissionPager<'b> {
|
||||||
self.viewer,
|
self.viewer,
|
||||||
&self.store.store,
|
&self.store.store,
|
||||||
self.cache,
|
self.cache,
|
||||||
|
true,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -231,6 +240,7 @@ fn filter_submissions<'a>(
|
||||||
viewer: Option<Uuid>,
|
viewer: Option<Uuid>,
|
||||||
store: &'a hyaenidae_profiles::store::Store,
|
store: &'a hyaenidae_profiles::store::Store,
|
||||||
cache: &'a mut Cache,
|
cache: &'a mut Cache,
|
||||||
|
show_unlisted: bool,
|
||||||
) -> impl FnMut(Uuid) -> Option<Uuid> + 'a {
|
) -> impl FnMut(Uuid) -> Option<Uuid> + 'a {
|
||||||
move |submission_id| {
|
move |submission_id| {
|
||||||
if !cache.submission_map.contains_key(&submission_id) {
|
if !cache.submission_map.contains_key(&submission_id) {
|
||||||
|
@ -241,7 +251,7 @@ fn filter_submissions<'a>(
|
||||||
cache.profile_map.insert(profile.id(), profile);
|
cache.profile_map.insert(profile.id(), profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
let opt = can_view(viewer, &submission, store, cache);
|
let opt = can_view(viewer, &submission, store, cache, show_unlisted);
|
||||||
|
|
||||||
if let Some(file_id) = submission.files().get(0) {
|
if let Some(file_id) = submission.files().get(0) {
|
||||||
if !cache.file_map.contains_key(file_id) {
|
if !cache.file_map.contains_key(file_id) {
|
||||||
|
@ -256,7 +266,7 @@ fn filter_submissions<'a>(
|
||||||
} else {
|
} else {
|
||||||
let submission = cache.submission_map.get(&submission_id)?.clone();
|
let submission = cache.submission_map.get(&submission_id)?.clone();
|
||||||
|
|
||||||
can_view(viewer, &submission, store, cache)?;
|
can_view(viewer, &submission, store, cache, show_unlisted)?;
|
||||||
|
|
||||||
Some(submission_id)
|
Some(submission_id)
|
||||||
}
|
}
|
||||||
|
@ -268,8 +278,12 @@ pub(crate) fn can_view(
|
||||||
submission: &Submission,
|
submission: &Submission,
|
||||||
store: &hyaenidae_profiles::store::Store,
|
store: &hyaenidae_profiles::store::Store,
|
||||||
cache: &mut Cache,
|
cache: &mut Cache,
|
||||||
|
show_unlisted: bool,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if let Some(viewer) = viewer {
|
if let Some(viewer) = viewer {
|
||||||
|
if viewer == submission.profile_id() {
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
if let Some(block) = cache.blocks.get(&submission.profile_id()) {
|
if let Some(block) = cache.blocks.get(&submission.profile_id()) {
|
||||||
if *block {
|
if *block {
|
||||||
return None;
|
return None;
|
||||||
|
@ -302,7 +316,7 @@ pub(crate) fn can_view(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if submission.is_followers_only() {
|
if (submission.is_unlisted() && !show_unlisted) || submission.is_followers_only() {
|
||||||
if let Some(follow) = cache.follows.get(&submission.profile_id()) {
|
if let Some(follow) = cache.follows.get(&submission.profile_id()) {
|
||||||
if !*follow {
|
if !*follow {
|
||||||
return None;
|
return None;
|
||||||
|
@ -323,6 +337,10 @@ pub(crate) fn can_view(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if submission.is_unlisted() && !show_unlisted {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let requires_login = if let Some(profile) = cache.profile_map.get(&submission.profile_id())
|
let requires_login = if let Some(profile) = cache.profile_map.get(&submission.profile_id())
|
||||||
{
|
{
|
||||||
profile.login_required()
|
profile.login_required()
|
||||||
|
|
|
@ -9,8 +9,8 @@ use crate::{
|
||||||
ActixLoader, State,
|
ActixLoader, State,
|
||||||
};
|
};
|
||||||
use actix_web::{client::Client, web, HttpRequest, HttpResponse, Scope};
|
use actix_web::{client::Client, web, HttpRequest, HttpResponse, Scope};
|
||||||
use hyaenidae_profiles::store::{File, Profile, Submission};
|
use hyaenidae_profiles::store::{File, Profile, Submission, Visibility};
|
||||||
use hyaenidae_toolkit::{Button, FileInput, TextInput, Tile};
|
use hyaenidae_toolkit::{Button, FileInput, Select, TextInput, Tile};
|
||||||
use i18n_embed_fl::fl;
|
use i18n_embed_fl::fl;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -312,6 +312,17 @@ impl SubmissionState {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn visibility(&self, loader: &ActixLoader) -> Select {
|
||||||
|
Select::new("visibility")
|
||||||
|
.title(&fl!(loader, "submission-visibility-select"))
|
||||||
|
.options(&[
|
||||||
|
(&fl!(loader, "submission-visibility-followers"), "Followers"),
|
||||||
|
(&fl!(loader, "submission-visibility-unlisted"), "Unlisted"),
|
||||||
|
(&fl!(loader, "submission-visibility-public"), "Public"),
|
||||||
|
])
|
||||||
|
.default_option(&self.submission.visibility().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn title_input(&self, loader: &ActixLoader) -> TextInput {
|
pub(crate) fn title_input(&self, loader: &ActixLoader) -> TextInput {
|
||||||
TextInput::new("title")
|
TextInput::new("title")
|
||||||
.title(&fl!(loader, "update-submission-title-input"))
|
.title(&fl!(loader, "update-submission-title-input"))
|
||||||
|
@ -690,40 +701,90 @@ fn submission_nav(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn adjacent_submissions(
|
async fn adjacent_submissions(
|
||||||
submission_id: Uuid,
|
viewer: Option<Uuid>,
|
||||||
is_published: bool,
|
submission: &Submission,
|
||||||
state: &State,
|
state: &State,
|
||||||
) -> Result<(Option<Uuid>, Option<Uuid>), Error> {
|
) -> Result<(Option<Uuid>, Option<Uuid>), Error> {
|
||||||
|
let submission_id = submission.id();
|
||||||
|
let is_published = submission.published().is_some();
|
||||||
let store = state.profiles.clone();
|
let store = state.profiles.clone();
|
||||||
let (next, prev) = web::block(move || {
|
let (next, prev) = web::block(move || {
|
||||||
if is_published {
|
if is_published {
|
||||||
|
let inner_store = store.clone();
|
||||||
let prev = store
|
let prev = store
|
||||||
.store
|
.store
|
||||||
.submissions
|
.submissions
|
||||||
.published_newer_than_for_profile(submission_id)
|
.published_newer_than_for_profile(submission_id)
|
||||||
.filter(|id| *id != submission_id)
|
.filter(|id| *id != submission_id)
|
||||||
.next();
|
.find_map(move |id| {
|
||||||
|
let submission = inner_store.store.submissions.by_id(id).ok()??;
|
||||||
|
|
||||||
|
crate::pagination::submission::can_view(
|
||||||
|
viewer,
|
||||||
|
&submission,
|
||||||
|
&inner_store.store,
|
||||||
|
&mut Default::default(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map(move |_| id)
|
||||||
|
});
|
||||||
|
|
||||||
let next = store
|
let next = store
|
||||||
.store
|
.store
|
||||||
.submissions
|
.submissions
|
||||||
.published_older_than_for_profile(submission_id)
|
.published_older_than_for_profile(submission_id)
|
||||||
.filter(|id| *id != submission_id)
|
.filter(|id| *id != submission_id)
|
||||||
.next();
|
.find_map(move |id| {
|
||||||
|
let submission = store.store.submissions.by_id(id).ok()??;
|
||||||
|
|
||||||
|
crate::pagination::submission::can_view(
|
||||||
|
viewer,
|
||||||
|
&submission,
|
||||||
|
&store.store,
|
||||||
|
&mut Default::default(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map(move |_| id)
|
||||||
|
});
|
||||||
|
|
||||||
Ok((next, prev)) as Result<_, Error>
|
Ok((next, prev)) as Result<_, Error>
|
||||||
} else {
|
} else {
|
||||||
|
let inner_store = store.clone();
|
||||||
let prev = store
|
let prev = store
|
||||||
.store
|
.store
|
||||||
.submissions
|
.submissions
|
||||||
.drafted_newer_than_for_profile(submission_id)
|
.drafted_newer_than_for_profile(submission_id)
|
||||||
.filter(|id| *id != submission_id)
|
.filter(|id| *id != submission_id)
|
||||||
.next();
|
.find_map(move |id| {
|
||||||
|
let submission = inner_store.store.submissions.by_id(id).ok()??;
|
||||||
|
|
||||||
|
crate::pagination::submission::can_view(
|
||||||
|
viewer,
|
||||||
|
&submission,
|
||||||
|
&inner_store.store,
|
||||||
|
&mut Default::default(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map(move |_| id)
|
||||||
|
});
|
||||||
|
|
||||||
let next = store
|
let next = store
|
||||||
.store
|
.store
|
||||||
.submissions
|
.submissions
|
||||||
.drafted_older_than_for_profile(submission_id)
|
.drafted_older_than_for_profile(submission_id)
|
||||||
.filter(|id| *id != submission_id)
|
.filter(|id| *id != submission_id)
|
||||||
.next();
|
.find_map(move |id| {
|
||||||
|
let submission = store.store.submissions.by_id(id).ok()??;
|
||||||
|
|
||||||
|
crate::pagination::submission::can_view(
|
||||||
|
viewer,
|
||||||
|
&submission,
|
||||||
|
&store.store,
|
||||||
|
&mut Default::default(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.map(move |_| id)
|
||||||
|
});
|
||||||
|
|
||||||
Ok((next, prev)) as Result<_, Error>
|
Ok((next, prev)) as Result<_, Error>
|
||||||
}
|
}
|
||||||
|
@ -762,7 +823,7 @@ async fn submission_page(
|
||||||
}
|
}
|
||||||
|
|
||||||
let (next_submission, previous_submission) =
|
let (next_submission, previous_submission) =
|
||||||
adjacent_submissions(submission.id(), submission.published().is_some(), &state).await?;
|
adjacent_submissions(viewer, &submission, &state).await?;
|
||||||
|
|
||||||
let (nav, current_file) = submission_nav(
|
let (nav, current_file) = submission_nav(
|
||||||
page.map(|p| p.into_inner()),
|
page.map(|p| p.into_inner()),
|
||||||
|
@ -895,7 +956,7 @@ async fn create_comment(
|
||||||
let cache = files_for_profile(&poster, cache, &state).await?;
|
let cache = files_for_profile(&poster, cache, &state).await?;
|
||||||
|
|
||||||
let (next_submission, previous_submission) =
|
let (next_submission, previous_submission) =
|
||||||
adjacent_submissions(submission.id(), submission.published().is_some(), &state).await?;
|
adjacent_submissions(Some(profile.id()), &submission, &state).await?;
|
||||||
|
|
||||||
let (nav, current_file) = submission_nav(
|
let (nav, current_file) = submission_nav(
|
||||||
page.map(|p| p.into_inner()),
|
page.map(|p| p.into_inner()),
|
||||||
|
@ -932,6 +993,7 @@ async fn create_comment(
|
||||||
struct UpdateSubmissionForm {
|
struct UpdateSubmissionForm {
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
|
visibility: Option<Visibility>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_submission(
|
async fn update_submission(
|
||||||
|
@ -962,6 +1024,7 @@ async fn update_submission(
|
||||||
submission.id(),
|
submission.id(),
|
||||||
form.title.clone(),
|
form.title.clone(),
|
||||||
Some(form.description.clone()),
|
Some(form.description.clone()),
|
||||||
|
form.visibility,
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,18 @@
|
||||||
@(loader: &ActixLoader, browse_view: &ViewBrowseState, nav_state: &NavState)
|
@(loader: &ActixLoader, browse_view: &ViewBrowseState, nav_state: &NavState)
|
||||||
|
|
||||||
@:wide(loader, &fl!(loader, "site-name"), &fl!(loader, "site-description"), nav_state, {}, {
|
@:wide(loader, &fl!(loader, "site-name"), &fl!(loader, "site-description"), nav_state, {}, {
|
||||||
<div class="tabs">
|
@if browse_view.is_logged_in() {
|
||||||
@:tab_group({
|
<div class="tabs">
|
||||||
@:tab(Tab::new("/browse").selected(true), {
|
@:tab_group({
|
||||||
@fl!(loader, "submissions-tab")
|
@:tab(Tab::new("/browse").selected(true), {
|
||||||
|
@fl!(loader, "submissions-tab")
|
||||||
|
})
|
||||||
|
@:tab(Tab::new("/discover"), {
|
||||||
|
@fl!(loader, "profiles-tab")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@:tab(Tab::new("/discover"), {
|
</div>
|
||||||
@fl!(loader, "profiles-tab")
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
</div>
|
|
||||||
@if browse_view.has_submissions() {
|
@if browse_view.has_submissions() {
|
||||||
@if browse_view.has_nav() {
|
@if browse_view.has_nav() {
|
||||||
@:thumbnail_border({
|
@:thumbnail_border({
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
@use crate::ActixLoader;
|
@use crate::ActixLoader;
|
||||||
@use crate::templates::{button_js, file_js};
|
@use crate::templates::{button_js, file_js};
|
||||||
@use crate::{templates::layouts::home, nav::NavState, submissions::SubmissionState};
|
@use crate::{templates::layouts::home, nav::NavState, submissions::SubmissionState};
|
||||||
@use hyaenidae_toolkit::{templates::{button_group, card, card_body, card_title, file_input, text_input}, Button, Card};
|
@use hyaenidae_toolkit::{templates::{button_group}, Button};
|
||||||
|
@use hyaenidae_toolkit::{templates::{card, card_body, card_title}, Card};
|
||||||
|
@use hyaenidae_toolkit::templates::file_input;
|
||||||
|
@use hyaenidae_toolkit::templates::select;
|
||||||
|
@use hyaenidae_toolkit::templates::text_input;
|
||||||
@use hyaenidae_toolkit::templates::image;
|
@use hyaenidae_toolkit::templates::image;
|
||||||
@use i18n_embed_fl::fl;
|
@use i18n_embed_fl::fl;
|
||||||
|
|
||||||
|
@ -39,6 +43,9 @@
|
||||||
@:card_body({
|
@:card_body({
|
||||||
@:text_input(&state.title_input(loader).dark(nav_state.dark()))
|
@:text_input(&state.title_input(loader).dark(nav_state.dark()))
|
||||||
@:text_input(&state.description_input(loader).dark(nav_state.dark()))
|
@:text_input(&state.description_input(loader).dark(nav_state.dark()))
|
||||||
|
@if !state.is_published() {
|
||||||
|
@:select(&state.visibility(loader).dark(nav_state.dark()))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
@:card_body({
|
@:card_body({
|
||||||
@:button_group(&[
|
@:button_group(&[
|
||||||
|
|
|
@ -169,6 +169,11 @@ create-submission-heading = Select a file to post
|
||||||
create-submission-input = Select Image
|
create-submission-input = Select Image
|
||||||
create-submission-button = Next
|
create-submission-button = Next
|
||||||
|
|
||||||
|
submission-visibility-select = Visibility
|
||||||
|
submission-visibility-followers = Followers Only
|
||||||
|
submission-visibility-unlisted = Unlisted
|
||||||
|
submission-visibility-public = Public
|
||||||
|
|
||||||
update-submission-title = Edit Submission
|
update-submission-title = Edit Submission
|
||||||
update-submission-subtitle = Edit information or update images
|
update-submission-subtitle = Edit information or update images
|
||||||
update-submission-publish-title = Publish Submission
|
update-submission-publish-title = Publish Submission
|
||||||
|
|
Loading…
Reference in a new issue