Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/583 add withdrawn date #594

Merged
merged 15 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- [583](https://github.com/thoth-pub/thoth/issues/583) - Add new field, Permanently Withdrawn Date, to Work for Out-of-print or Withdrawn from Sale Works.

### Changed
- [218](https://github.com/thoth-pub/thoth/issues/218) - Make series ISSN optional

Expand Down
7 changes: 7 additions & 0 deletions thoth-api/migrations/v0.12.3/down.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ ALTER TABLE series

ALTER TABLE series
ALTER COLUMN issn_digital SET NOT NULL;

ALTER TABLE work
DROP CONSTRAINT work_active_withdrawn_date_check,
DROP CONSTRAINT work_inactive_no_withdrawn_date_check,
DROP CONSTRAINT work_withdrawn_date_after_publication_date_check,
DROP COLUMN withdrawn_date;

19 changes: 19 additions & 0 deletions thoth-api/migrations/v0.12.3/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,22 @@ ALTER TABLE series
ALTER TABLE series
ALTER COLUMN issn_digital DROP NOT NULL;

ALTER TABLE work
ADD COLUMN withdrawn_date DATE;

UPDATE work
SET withdrawn_date = updated_at
WHERE (work_status = 'withdrawn-from-sale'
OR work_status = 'out-of-print');

ALTER TABLE work
ADD CONSTRAINT work_active_withdrawn_date_check CHECK
((work_status = 'withdrawn-from-sale' OR work_status = 'out-of-print')
brendan-oconnell marked this conversation as resolved.
Show resolved Hide resolved
OR (work_status NOT IN ('withdrawn-from-sale', 'out-of-print') AND withdrawn_date IS NULL)),

ADD CONSTRAINT work_inactive_no_withdrawn_date_check CHECK
(((work_status = 'withdrawn-from-sale' OR work_status = 'out-of-print') AND withdrawn_date IS NOT NULL)
OR (work_status NOT IN ('withdrawn-from-sale', 'out-of-print'))),

ADD CONSTRAINT work_withdrawn_date_after_publication_date_check CHECK
(withdrawn_date IS NULL OR (publication_date < withdrawn_date));
15 changes: 14 additions & 1 deletion thoth-api/src/graphql/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::model::publisher::*;
use crate::model::reference::*;
use crate::model::series::*;
use crate::model::subject::*;
use crate::model::work::crud::WorkValidation;
use crate::model::work::*;
use crate::model::work_relation::*;
use crate::model::Convert;
Expand Down Expand Up @@ -1516,6 +1517,8 @@ impl MutationRoot {
.account_access
.can_edit(publisher_id_from_imprint_id(&context.db, data.imprint_id)?)?;

data.validate()?;

Work::create(&context.db, &data).map_err(|e| e.into())
}

Expand Down Expand Up @@ -1705,17 +1708,20 @@ impl MutationRoot {
work.can_be_chapter(&context.db)?;
}

data.validate()?;
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) {
Ok(w) => {
// update chapters if their pub. data or work_status doesn't match the parent's
// update chapters if their pub. data, withdrawn_date or work_status doesn't match the parent's
for child in work.children(&context.db)? {
if child.publication_date != w.publication_date
|| child.work_status != w.work_status
|| child.withdrawn_date != w.withdrawn_date
{
let mut data: PatchWork = child.clone().into();
data.publication_date = w.publication_date;
data.withdrawn_date = w.withdrawn_date;
data.work_status = w.work_status.clone();
child.update(&context.db, &data, &account_id)?;
}
Expand Down Expand Up @@ -2279,6 +2285,13 @@ impl Work {
self.publication_date
}

#[graphql(
description = "Date a work was withdrawn from publication. Only applies to out of print and withdrawn from sale works."
)]
pub fn withdrawn_date(&self) -> Option<NaiveDate> {
self.withdrawn_date
}

pub fn place(&self) -> Option<&String> {
self.place.as_ref()
}
Expand Down
23 changes: 21 additions & 2 deletions thoth-api/src/model/work/crud.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
NewWork, NewWorkHistory, PatchWork, Work, WorkField, WorkHistory, WorkOrderBy, WorkStatus,
WorkType,
NewWork, NewWorkHistory, PatchWork, Work, WorkField, WorkHistory, WorkOrderBy, WorkProperties,
WorkStatus, WorkType,
};
use crate::graphql::model::TimeExpression;
use crate::graphql::utils::{Direction, Expression};
Expand Down Expand Up @@ -176,6 +176,10 @@ impl Crud for Work {
Direction::Asc => query.order(dsl::publication_date.asc()),
Direction::Desc => query.order(dsl::publication_date.desc()),
},
WorkField::WithdrawnDate => match order.direction {
Direction::Asc => query.order(dsl::withdrawn_date.asc()),
Direction::Desc => query.order(dsl::withdrawn_date.desc()),
},
WorkField::Place => match order.direction {
Direction::Asc => query.order(dsl::place.asc()),
Direction::Desc => query.order(dsl::place.desc()),
Expand Down Expand Up @@ -399,6 +403,21 @@ impl DbInsert for NewWorkHistory {
db_insert!(work_history::table);
}

pub trait WorkValidation
where
Self: WorkProperties,
{
fn validate(&self) -> ThothResult<()> {
self.withdrawn_date_error()?;
self.no_withdrawn_date_error()?;
self.withdrawn_date_before_publication_date_error()
}
}

impl WorkValidation for NewWork {}

impl WorkValidation for PatchWork {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
101 changes: 101 additions & 0 deletions thoth-api/src/model/work/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use std::fmt;
use strum::Display;
use strum::EnumString;
use thoth_errors::{ThothError, ThothResult};
use uuid::Uuid;

use crate::graphql::utils::Direction;
Expand Down Expand Up @@ -98,6 +99,7 @@ pub enum WorkField {
#[strum(serialize = "DOI")]
Doi,
PublicationDate,
WithdrawnDate,
Place,
PageCount,
PageBreakdown,
Expand Down Expand Up @@ -144,6 +146,7 @@ pub struct Work {
pub imprint_id: Uuid,
pub doi: Option<Doi>,
pub publication_date: Option<NaiveDate>,
pub withdrawn_date: Option<NaiveDate>,
pub place: Option<String>,
pub page_count: Option<i32>,
pub page_breakdown: Option<String>,
Expand Down Expand Up @@ -184,6 +187,7 @@ pub struct WorkWithRelations {
pub edition: Option<i32>,
pub doi: Option<Doi>,
pub publication_date: Option<String>,
pub withdrawn_date: Option<String>,
pub place: Option<String>,
pub page_count: Option<i32>,
pub page_breakdown: Option<String>,
Expand Down Expand Up @@ -234,6 +238,7 @@ pub struct NewWork {
pub imprint_id: Uuid,
pub doi: Option<Doi>,
pub publication_date: Option<NaiveDate>,
pub withdrawn_date: Option<NaiveDate>,
pub place: Option<String>,
pub page_count: Option<i32>,
pub page_breakdown: Option<String>,
Expand Down Expand Up @@ -275,6 +280,7 @@ pub struct PatchWork {
pub imprint_id: Uuid,
pub doi: Option<Doi>,
pub publication_date: Option<NaiveDate>,
pub withdrawn_date: Option<NaiveDate>,
pub place: Option<String>,
pub page_count: Option<i32>,
pub page_breakdown: Option<String>,
Expand Down Expand Up @@ -326,6 +332,93 @@ pub struct WorkOrderBy {
pub direction: Direction,
}

impl WorkStatus {
fn is_withdrawn_out_of_print(&self) -> bool {
matches!(self, WorkStatus::OutOfPrint | WorkStatus::WithdrawnFromSale)
}
}

pub trait WorkProperties {
fn work_status(&self) -> &WorkStatus;
fn publication_date(&self) -> &Option<NaiveDate>;
fn withdrawn_date(&self) -> &Option<NaiveDate>;

fn is_withdrawn_out_of_print(&self) -> bool {
self.work_status().is_withdrawn_out_of_print()
}

fn has_withdrawn_date(&self) -> bool {
self.withdrawn_date().is_some()
}

fn withdrawn_date_error(&self) -> ThothResult<()> {
if !self.is_withdrawn_out_of_print() && self.has_withdrawn_date() {
return Err(ThothError::WithdrawnDateError);
}
Ok(())
}

fn no_withdrawn_date_error(&self) -> ThothResult<()> {
if self.is_withdrawn_out_of_print() && !self.has_withdrawn_date() {
return Err(ThothError::NoWithdrawnDateError);
}
Ok(())
}

fn withdrawn_date_before_publication_date_error(&self) -> ThothResult<()> {
if let (Some(withdrawn_date), Some(publication_date)) =
(self.withdrawn_date(), self.publication_date())
{
if withdrawn_date < publication_date {
return Err(ThothError::WithdrawnDateBeforePublicationDateError);
}
}
Ok(())
}
}

impl WorkProperties for Work {
fn work_status(&self) -> &WorkStatus {
&self.work_status
}

fn withdrawn_date(&self) -> &Option<NaiveDate> {
&self.withdrawn_date
}

fn publication_date(&self) -> &Option<NaiveDate> {
&self.publication_date
}
}

impl WorkProperties for NewWork {
fn work_status(&self) -> &WorkStatus {
&self.work_status
}

fn withdrawn_date(&self) -> &Option<NaiveDate> {
&self.withdrawn_date
}

fn publication_date(&self) -> &Option<NaiveDate> {
&self.publication_date
}
}

impl WorkProperties for PatchWork {
fn work_status(&self) -> &WorkStatus {
&self.work_status
}

fn withdrawn_date(&self) -> &Option<NaiveDate> {
&self.withdrawn_date
}

fn publication_date(&self) -> &Option<NaiveDate> {
&self.publication_date
}
}

impl Work {
pub fn compile_fulltitle(&self) -> String {
if let Some(subtitle) = &self.subtitle.clone() {
Expand Down Expand Up @@ -376,6 +469,7 @@ impl From<Work> for PatchWork {
imprint_id: w.imprint_id,
doi: w.doi,
publication_date: w.publication_date,
withdrawn_date: w.withdrawn_date,
place: w.place,
page_count: w.page_count,
page_breakdown: w.page_breakdown,
Expand Down Expand Up @@ -480,6 +574,7 @@ fn test_workfield_display() {
assert_eq!(format!("{}", WorkField::Edition), "Edition");
assert_eq!(format!("{}", WorkField::Doi), "DOI");
assert_eq!(format!("{}", WorkField::PublicationDate), "PublicationDate");
assert_eq!(format!("{}", WorkField::WithdrawnDate), "WithdrawnDate");
assert_eq!(format!("{}", WorkField::Place), "Place");
assert_eq!(format!("{}", WorkField::PageCount), "PageCount");
assert_eq!(format!("{}", WorkField::PageBreakdown), "PageBreakdown");
Expand Down Expand Up @@ -621,6 +716,10 @@ fn test_workfield_fromstr() {
WorkField::from_str("PublicationDate").unwrap(),
WorkField::PublicationDate
);
assert_eq!(
WorkField::from_str("WithdrawnDate").unwrap(),
WorkField::WithdrawnDate
);
assert_eq!(WorkField::from_str("Place").unwrap(), WorkField::Place);
assert_eq!(
WorkField::from_str("PageCount").unwrap(),
Expand Down Expand Up @@ -727,6 +826,7 @@ fn test_work_into_patchwork() {
imprint_id: Uuid::parse_str("00000000-0000-0000-BBBB-000000000002").unwrap(),
doi: Some(Doi::from_str("https://doi.org/10.00001/BOOK.0001").unwrap()),
publication_date: chrono::NaiveDate::from_ymd_opt(1999, 12, 31),
withdrawn_date: None,
place: Some("León, Spain".to_string()),
page_count: Some(123),
page_breakdown: None,
Expand Down Expand Up @@ -766,6 +866,7 @@ fn test_work_into_patchwork() {
assert_eq!(work.imprint_id, patch_work.imprint_id);
assert_eq!(work.doi, patch_work.doi);
assert_eq!(work.publication_date, patch_work.publication_date);
assert_eq!(work.withdrawn_date, patch_work.withdrawn_date);
assert_eq!(work.place, patch_work.place);
assert_eq!(work.page_count, patch_work.page_count);
assert_eq!(work.page_breakdown, patch_work.page_breakdown);
Expand Down
1 change: 1 addition & 0 deletions thoth-api/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ table! {
imprint_id -> Uuid,
doi -> Nullable<Text>,
publication_date -> Nullable<Date>,
withdrawn_date -> Nullable<Date>,
place -> Nullable<Text>,
page_count -> Nullable<Int4>,
page_breakdown -> Nullable<Text>,
Expand Down
Loading
Loading