Skip to content

Commit

Permalink
Add a warning dialogue before a non-superuser can change an unpublish…
Browse files Browse the repository at this point in the history
…ed Work to published
  • Loading branch information
brendan-oconnell committed Dec 16, 2024
1 parent c45e2c4 commit fde822b
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 6 deletions.
17 changes: 17 additions & 0 deletions thoth-api/src/graphql/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,23 @@ impl MutationRoot {
}

data.validate()?;

let is_data_unpublished =
data.work_status == WorkStatus::Forthcoming ||
data.work_status == WorkStatus::Cancelled||
data.work_status == WorkStatus::PostponedIndefinitely;

let is_work_published =
work.work_status == WorkStatus::Active ||
work.work_status == WorkStatus::Withdrawn ||
work.work_status == WorkStatus::Superseded;

// return an error if a non-superuser attempts to change the
// Work Status of a published Work to unpublished
if is_work_published && is_data_unpublished && !context.account_access.is_superuser {
return Err(ThothError::ThothSetWorkStatusError.into());
}

let account_id = context.token.jwt.as_ref().unwrap().account_id(&context.db);
// update the work and, if it succeeds, synchronise its children statuses and pub. date
match work.update(&context.db, &data, &account_id) {
Expand Down
1 change: 1 addition & 0 deletions thoth-app/src/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,4 +495,5 @@ pub mod serieses;
pub mod subjects_form;
pub mod utils;
pub mod work;
pub mod work_status_dialogue;
pub mod works;
37 changes: 31 additions & 6 deletions thoth-app/src/component/work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use crate::component::utils::FormUrlInput;
use crate::component::utils::FormWorkStatusSelect;
use crate::component::utils::FormWorkTypeSelect;
use crate::component::utils::Loader;
use crate::component::work_status_dialogue::ConfirmWorkStatusComponent;
use crate::models::work::delete_work_mutation::DeleteWorkRequest;
use crate::models::work::delete_work_mutation::DeleteWorkRequestBody;
use crate::models::work::delete_work_mutation::PushActionDeleteWork;
Expand Down Expand Up @@ -83,6 +84,8 @@ pub struct WorkComponent {
imprint_id: Uuid,
// Track work_type stored in database, as distinct from work_type selected in dropdown
work_type: WorkType,
// Track work_status stored in database, as distinct from work_status selected in dropdown
current_work_status: WorkStatus,
data: WorkFormData,
fetch_work: FetchWork,
push_work: PushUpdateWork,
Expand Down Expand Up @@ -169,6 +172,7 @@ impl Component for WorkComponent {
let doi_warning = Default::default();
let imprint_id = work.imprint.imprint_id;
let work_type = work.work_type;
let current_work_status = work.work_status;
let data: WorkFormData = Default::default();
let resource_access = ctx.props().current_user.resource_access.clone();
let work_id = ctx.props().work_id;
Expand All @@ -181,6 +185,7 @@ impl Component for WorkComponent {
doi_warning,
imprint_id,
work_type,
current_work_status,
data,
fetch_work,
push_work,
Expand All @@ -207,6 +212,7 @@ impl Component for WorkComponent {
self.doi = self.work.doi.clone().unwrap_or_default().to_string();
self.imprint_id = self.work.imprint.imprint_id;
self.work_type = self.work.work_type;
self.current_work_status = self.work.work_status;
body.data.imprints.clone_into(&mut self.data.imprints);
body.data
.work_types
Expand Down Expand Up @@ -575,14 +581,20 @@ impl Component for WorkComponent {
true => vec![WorkType::BookChapter],
false => vec![],
};
// Grey out chapter-specific or "book"-specific fields

// Variables required to grey out chapter-specific or "book"-specific fields
// based on currently selected work type.
let is_chapter = self.work.work_type == WorkType::BookChapter;
let is_not_withdrawn_or_superseded = self.work.work_status != WorkStatus::Withdrawn
&& self.work.work_status != WorkStatus::Superseded;
let is_active_withdrawn_or_superseded = self.work.work_status == WorkStatus::Active
let is_published = self.work.work_status == WorkStatus::Active
|| self.work.work_status == WorkStatus::Withdrawn
|| self.work.work_status == WorkStatus::Superseded;

let current_state_unpublished = self.current_work_status == WorkStatus::Forthcoming ||
self.current_work_status == WorkStatus::PostponedIndefinitely ||
self.current_work_status == WorkStatus::Cancelled;

html! {
<>
<nav class="level">
Expand Down Expand Up @@ -657,7 +669,7 @@ impl Component for WorkComponent {
label = "Publication Date"
value={ self.work.publication_date.clone() }
oninput={ ctx.link().callback(|e: InputEvent| Msg::ChangeDate(e.to_value())) }
required = { is_active_withdrawn_or_superseded }
required = { is_published }
/>
<FormDateInput
label = "Withdrawn Date"
Expand Down Expand Up @@ -821,9 +833,22 @@ impl Component for WorkComponent {

<div class="field">
<div class="control">
<button class="button is-success" type="submit">
{ SAVE_BUTTON }
</button>
// if the Work is unpublished (forthcoming, postponed, cancelled)
// and non-superuser sets to published (active, withdrawn, superseded),
// display warning dialogue
if !ctx.props().current_user.resource_access.is_superuser
&& current_state_unpublished
&& is_published
{
<ConfirmWorkStatusComponent
onclick={ ctx.link().callback(|_| Msg::UpdateWork) }
object_name={ self.work.full_title.clone() }
/>
} else {
<button class="button is-success" type="submit">
{ SAVE_BUTTON }
</button>
}
</div>
</div>
</form>
Expand Down
103 changes: 103 additions & 0 deletions thoth-app/src/component/work_status_dialogue.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::string::CANCEL_BUTTON;
use crate::string::SAVE_BUTTON;
use yew::html;
use yew::prelude::*;

pub struct ConfirmWorkStatusComponent {
show: bool,
}

#[derive(PartialEq, Properties)]
pub struct Props {
pub onclick: Option<Callback<MouseEvent>>,
pub object_name: String,
#[prop_or_default]
pub deactivated: bool,
}

pub enum Msg {
ToggleConfirmWorkStatusDisplay(bool),
}

impl Component for ConfirmWorkStatusComponent {
type Message = Msg;
type Properties = Props;

fn create(_ctx: &Context<Self>) -> Self {
ConfirmWorkStatusComponent { show: false }
}

fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::ToggleConfirmWorkStatusDisplay(value) => {
self.show = value;
true
}
}
}

fn view(&self, ctx: &Context<Self>) -> Html {
let open_modal = ctx.link().callback(|e: MouseEvent| {
e.prevent_default();
Msg::ToggleConfirmWorkStatusDisplay(true)
});
let close_modal = ctx.link().callback(|e: MouseEvent| {
e.prevent_default();
Msg::ToggleConfirmWorkStatusDisplay(false)
});
html! {
<>
<button
class="button is-success"
onclick={ open_modal }
disabled={ ctx.props().deactivated }
>
{ SAVE_BUTTON }
</button>
<div class={ self.confirm_work_status_status() }>
<div class="modal-background" onclick={ &close_modal }></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">{ "Confirm changing work status" }</p>
<button
class="delete"
aria-label="close"
onclick={ &close_modal }
></button>
</header>
<section class="modal-card-body">
<p>
{ "Are you sure you want to change the work status to Active for " }
<i>{ &ctx.props().object_name }</i>
{ "?" }
</p>
</section>
<footer class="modal-card-foot">
<button
class="button is-success"
onclick={ ctx.props().onclick.clone() }
>
{ SAVE_BUTTON }
</button>
<button
class="button"
onclick={ &close_modal }
>
{ CANCEL_BUTTON }
</button>
</footer>
</div>
</div>
</>
}
}
}

impl ConfirmWorkStatusComponent {
fn confirm_work_status_status(&self) -> String {
match self.show {
true => "modal is-active".to_string(),
false => "modal".to_string(),
}
}
}
2 changes: 2 additions & 0 deletions thoth-errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ pub enum ThothError {
ThothLocationError,
#[error("Only superusers can update the canonical location when Thoth Location Platform is already set as canonical.")]
ThothUpdateCanonicalError,
#[error("Once a Work has been published, it cannot return to an unpublished Work Status.")]
ThothSetWorkStatusError,
}

impl ThothError {
Expand Down

0 comments on commit fde822b

Please sign in to comment.